aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorWladimir J. van der Laan <laanwj@gmail.com>2011-05-14 20:10:21 +0200
committerWladimir J. van der Laan <laanwj@gmail.com>2011-05-14 20:10:21 +0200
commit69d605f410c83235aa7b757445e7d0166fcfe2d9 (patch)
tree577e034f248830a2a6e118a80962286d0b0e49dd /core
parent2097c09a9b5dda5bfa0de1906a8c155c3c3b529b (diff)
downloadbitcoin-69d605f410c83235aa7b757445e7d0166fcfe2d9.tar.xz
integration of core bitcoin
Diffstat (limited to 'core')
-rw-r--r--core/include/db.h526
-rw-r--r--core/include/headers.h147
-rw-r--r--core/include/init.h11
-rw-r--r--core/include/irc.h13
-rw-r--r--core/include/key.h18
-rw-r--r--core/include/main.h204
-rw-r--r--core/include/noui.h67
-rw-r--r--core/include/rpc.h6
-rw-r--r--core/include/script.h718
-rw-r--r--core/src/db.cpp1026
-rw-r--r--core/src/init.cpp522
-rw-r--r--core/src/irc.cpp438
-rw-r--r--core/src/main.cpp4024
-rw-r--r--core/src/net.cpp1665
-rw-r--r--core/src/rpc.cpp2195
-rw-r--r--core/src/script.cpp1208
-rw-r--r--core/src/util.cpp21
17 files changed, 12686 insertions, 123 deletions
diff --git a/core/include/db.h b/core/include/db.h
new file mode 100644
index 0000000000..9826194ed0
--- /dev/null
+++ b/core/include/db.h
@@ -0,0 +1,526 @@
+// 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_DB_H
+#define BITCOIN_DB_H
+
+#include "key.h"
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include <db_cxx.h>
+
+class CTransaction;
+class CTxIndex;
+class CDiskBlockIndex;
+class CDiskTxPos;
+class COutPoint;
+class CUser;
+class CReview;
+class CAddress;
+class CWalletTx;
+class CAccount;
+class CAccountingEntry;
+class CBlockLocator;
+
+extern std::map<std::string, std::string> mapAddressBook;
+extern CCriticalSection cs_mapAddressBook;
+extern std::vector<unsigned char> vchDefaultKey;
+extern bool fClient;
+extern int nBestHeight;
+
+
+extern unsigned int nWalletDBUpdated;
+extern DbEnv dbenv;
+
+
+extern void DBFlush(bool fShutdown);
+extern std::vector<unsigned char> GetKeyFromKeyPool();
+extern int64 GetOldestKeyPoolTime();
+
+
+
+
+class CDB
+{
+protected:
+ Db* pdb;
+ std::string strFile;
+ std::vector<DbTxn*> vTxn;
+ bool fReadOnly;
+
+ explicit CDB(const char* pszFile, const char* pszMode="r+");
+ ~CDB() { Close(); }
+public:
+ void Close();
+private:
+ CDB(const CDB&);
+ void operator=(const CDB&);
+
+protected:
+ template<typename K, typename T>
+ bool Read(const K& key, T& value)
+ {
+ if (!pdb)
+ return false;
+
+ // Key
+ CDataStream ssKey(SER_DISK);
+ ssKey.reserve(1000);
+ ssKey << key;
+ Dbt datKey(&ssKey[0], ssKey.size());
+
+ // Read
+ Dbt datValue;
+ datValue.set_flags(DB_DBT_MALLOC);
+ int ret = pdb->get(GetTxn(), &datKey, &datValue, 0);
+ memset(datKey.get_data(), 0, datKey.get_size());
+ if (datValue.get_data() == NULL)
+ return false;
+
+ // Unserialize value
+ CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK);
+ ssValue >> value;
+
+ // Clear and free memory
+ memset(datValue.get_data(), 0, datValue.get_size());
+ free(datValue.get_data());
+ return (ret == 0);
+ }
+
+ template<typename K, typename T>
+ bool Write(const K& key, const T& value, bool fOverwrite=true)
+ {
+ if (!pdb)
+ return false;
+ if (fReadOnly)
+ assert(("Write called on database in read-only mode", false));
+
+ // Key
+ CDataStream ssKey(SER_DISK);
+ ssKey.reserve(1000);
+ ssKey << key;
+ Dbt datKey(&ssKey[0], ssKey.size());
+
+ // Value
+ CDataStream ssValue(SER_DISK);
+ ssValue.reserve(10000);
+ ssValue << value;
+ Dbt datValue(&ssValue[0], ssValue.size());
+
+ // Write
+ int ret = pdb->put(GetTxn(), &datKey, &datValue, (fOverwrite ? 0 : DB_NOOVERWRITE));
+
+ // Clear memory in case it was a private key
+ memset(datKey.get_data(), 0, datKey.get_size());
+ memset(datValue.get_data(), 0, datValue.get_size());
+ return (ret == 0);
+ }
+
+ template<typename K>
+ bool Erase(const K& key)
+ {
+ if (!pdb)
+ return false;
+ if (fReadOnly)
+ assert(("Erase called on database in read-only mode", false));
+
+ // Key
+ CDataStream ssKey(SER_DISK);
+ ssKey.reserve(1000);
+ ssKey << key;
+ Dbt datKey(&ssKey[0], ssKey.size());
+
+ // Erase
+ int ret = pdb->del(GetTxn(), &datKey, 0);
+
+ // Clear memory
+ memset(datKey.get_data(), 0, datKey.get_size());
+ return (ret == 0 || ret == DB_NOTFOUND);
+ }
+
+ template<typename K>
+ bool Exists(const K& key)
+ {
+ if (!pdb)
+ return false;
+
+ // Key
+ CDataStream ssKey(SER_DISK);
+ ssKey.reserve(1000);
+ ssKey << key;
+ Dbt datKey(&ssKey[0], ssKey.size());
+
+ // Exists
+ int ret = pdb->exists(GetTxn(), &datKey, 0);
+
+ // Clear memory
+ memset(datKey.get_data(), 0, datKey.get_size());
+ return (ret == 0);
+ }
+
+ Dbc* GetCursor()
+ {
+ if (!pdb)
+ return NULL;
+ Dbc* pcursor = NULL;
+ int ret = pdb->cursor(NULL, &pcursor, 0);
+ if (ret != 0)
+ return NULL;
+ return pcursor;
+ }
+
+ int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, unsigned int fFlags=DB_NEXT)
+ {
+ // Read at cursor
+ Dbt datKey;
+ if (fFlags == DB_SET || fFlags == DB_SET_RANGE || fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE)
+ {
+ datKey.set_data(&ssKey[0]);
+ datKey.set_size(ssKey.size());
+ }
+ Dbt datValue;
+ if (fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE)
+ {
+ datValue.set_data(&ssValue[0]);
+ datValue.set_size(ssValue.size());
+ }
+ datKey.set_flags(DB_DBT_MALLOC);
+ datValue.set_flags(DB_DBT_MALLOC);
+ int ret = pcursor->get(&datKey, &datValue, fFlags);
+ if (ret != 0)
+ return ret;
+ else if (datKey.get_data() == NULL || datValue.get_data() == NULL)
+ return 99999;
+
+ // Convert to streams
+ ssKey.SetType(SER_DISK);
+ ssKey.clear();
+ ssKey.write((char*)datKey.get_data(), datKey.get_size());
+ ssValue.SetType(SER_DISK);
+ ssValue.clear();
+ ssValue.write((char*)datValue.get_data(), datValue.get_size());
+
+ // Clear and free memory
+ memset(datKey.get_data(), 0, datKey.get_size());
+ memset(datValue.get_data(), 0, datValue.get_size());
+ free(datKey.get_data());
+ free(datValue.get_data());
+ return 0;
+ }
+
+ DbTxn* GetTxn()
+ {
+ if (!vTxn.empty())
+ return vTxn.back();
+ else
+ return NULL;
+ }
+
+public:
+ bool TxnBegin()
+ {
+ if (!pdb)
+ return false;
+ DbTxn* ptxn = NULL;
+ int ret = dbenv.txn_begin(GetTxn(), &ptxn, DB_TXN_NOSYNC);
+ if (!ptxn || ret != 0)
+ return false;
+ vTxn.push_back(ptxn);
+ return true;
+ }
+
+ bool TxnCommit()
+ {
+ if (!pdb)
+ return false;
+ if (vTxn.empty())
+ return false;
+ int ret = vTxn.back()->commit(0);
+ vTxn.pop_back();
+ return (ret == 0);
+ }
+
+ bool TxnAbort()
+ {
+ if (!pdb)
+ return false;
+ if (vTxn.empty())
+ return false;
+ int ret = vTxn.back()->abort();
+ vTxn.pop_back();
+ return (ret == 0);
+ }
+
+ bool ReadVersion(int& nVersion)
+ {
+ nVersion = 0;
+ return Read(std::string("version"), nVersion);
+ }
+
+ bool WriteVersion(int nVersion)
+ {
+ return Write(std::string("version"), nVersion);
+ }
+};
+
+
+
+
+
+
+
+
+class CTxDB : public CDB
+{
+public:
+ CTxDB(const char* pszMode="r+") : CDB("blkindex.dat", pszMode) { }
+private:
+ CTxDB(const CTxDB&);
+ void operator=(const CTxDB&);
+public:
+ bool ReadTxIndex(uint256 hash, CTxIndex& txindex);
+ bool UpdateTxIndex(uint256 hash, const CTxIndex& txindex);
+ bool AddTxIndex(const CTransaction& tx, const CDiskTxPos& pos, int nHeight);
+ bool EraseTxIndex(const CTransaction& tx);
+ bool ContainsTx(uint256 hash);
+ bool ReadOwnerTxes(uint160 hash160, int nHeight, std::vector<CTransaction>& vtx);
+ bool ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex);
+ bool ReadDiskTx(uint256 hash, CTransaction& tx);
+ bool ReadDiskTx(COutPoint outpoint, CTransaction& tx, CTxIndex& txindex);
+ bool ReadDiskTx(COutPoint outpoint, CTransaction& tx);
+ bool WriteBlockIndex(const CDiskBlockIndex& blockindex);
+ bool EraseBlockIndex(uint256 hash);
+ bool ReadHashBestChain(uint256& hashBestChain);
+ bool WriteHashBestChain(uint256 hashBestChain);
+ bool ReadBestInvalidWork(CBigNum& bnBestInvalidWork);
+ bool WriteBestInvalidWork(CBigNum bnBestInvalidWork);
+ bool LoadBlockIndex();
+};
+
+
+
+
+
+class CAddrDB : public CDB
+{
+public:
+ CAddrDB(const char* pszMode="r+") : CDB("addr.dat", pszMode) { }
+private:
+ CAddrDB(const CAddrDB&);
+ void operator=(const CAddrDB&);
+public:
+ bool WriteAddress(const CAddress& addr);
+ bool EraseAddress(const CAddress& addr);
+ bool LoadAddresses();
+};
+
+bool LoadAddresses();
+
+
+
+
+
+
+class CKeyPool
+{
+public:
+ int64 nTime;
+ std::vector<unsigned char> vchPubKey;
+
+ CKeyPool()
+ {
+ nTime = GetTime();
+ }
+
+ CKeyPool(const std::vector<unsigned char>& vchPubKeyIn)
+ {
+ nTime = GetTime();
+ vchPubKey = vchPubKeyIn;
+ }
+
+ IMPLEMENT_SERIALIZE
+ (
+ if (!(nType & SER_GETHASH))
+ READWRITE(nVersion);
+ READWRITE(nTime);
+ READWRITE(vchPubKey);
+ )
+};
+
+
+
+
+class CWalletDB : public CDB
+{
+public:
+ CWalletDB(const char* pszMode="r+") : CDB("wallet.dat", pszMode)
+ {
+ }
+private:
+ CWalletDB(const CWalletDB&);
+ void operator=(const CWalletDB&);
+public:
+ bool ReadName(const std::string& strAddress, std::string& strName)
+ {
+ strName = "";
+ return Read(std::make_pair(std::string("name"), strAddress), strName);
+ }
+
+ bool WriteName(const std::string& strAddress, const std::string& strName)
+ {
+ CRITICAL_BLOCK(cs_mapAddressBook)
+ mapAddressBook[strAddress] = strName;
+ nWalletDBUpdated++;
+ return Write(std::make_pair(std::string("name"), strAddress), strName);
+ }
+
+ bool EraseName(const std::string& strAddress)
+ {
+ // This should only be used for sending addresses, never for receiving addresses,
+ // receiving addresses must always have an address book entry if they're not change return.
+ CRITICAL_BLOCK(cs_mapAddressBook)
+ mapAddressBook.erase(strAddress);
+ nWalletDBUpdated++;
+ return Erase(std::make_pair(std::string("name"), strAddress));
+ }
+
+ bool ReadTx(uint256 hash, CWalletTx& wtx)
+ {
+ return Read(std::make_pair(std::string("tx"), hash), wtx);
+ }
+
+ bool WriteTx(uint256 hash, const CWalletTx& wtx)
+ {
+ nWalletDBUpdated++;
+ return Write(std::make_pair(std::string("tx"), hash), wtx);
+ }
+
+ bool EraseTx(uint256 hash)
+ {
+ nWalletDBUpdated++;
+ return Erase(std::make_pair(std::string("tx"), hash));
+ }
+
+ bool ReadKey(const std::vector<unsigned char>& vchPubKey, CPrivKey& vchPrivKey)
+ {
+ vchPrivKey.clear();
+ return Read(std::make_pair(std::string("key"), vchPubKey), vchPrivKey);
+ }
+
+ bool WriteKey(const std::vector<unsigned char>& vchPubKey, const CPrivKey& vchPrivKey)
+ {
+ nWalletDBUpdated++;
+ return Write(std::make_pair(std::string("key"), vchPubKey), vchPrivKey, false);
+ }
+
+ bool WriteBestBlock(const CBlockLocator& locator)
+ {
+ nWalletDBUpdated++;
+ return Write(std::string("bestblock"), locator);
+ }
+
+ bool ReadBestBlock(CBlockLocator& locator)
+ {
+ return Read(std::string("bestblock"), locator);
+ }
+
+ bool ReadDefaultKey(std::vector<unsigned char>& vchPubKey)
+ {
+ vchPubKey.clear();
+ return Read(std::string("defaultkey"), vchPubKey);
+ }
+
+ bool WriteDefaultKey(const std::vector<unsigned char>& vchPubKey)
+ {
+ vchDefaultKey = vchPubKey;
+ nWalletDBUpdated++;
+ return Write(std::string("defaultkey"), vchPubKey);
+ }
+
+ template<typename T>
+ bool ReadSetting(const std::string& strKey, T& value)
+ {
+ return Read(std::make_pair(std::string("setting"), strKey), value);
+ }
+
+ template<typename T>
+ bool WriteSetting(const std::string& strKey, const T& value)
+ {
+ nWalletDBUpdated++;
+ return Write(std::make_pair(std::string("setting"), strKey), value);
+ }
+
+ bool ReadAccount(const std::string& strAccount, CAccount& account);
+ bool WriteAccount(const std::string& strAccount, const CAccount& account);
+ bool WriteAccountingEntry(const CAccountingEntry& acentry);
+ int64 GetAccountCreditDebit(const std::string& strAccount);
+ void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& acentries);
+
+ bool LoadWallet();
+protected:
+ void ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool);
+ void KeepKey(int64 nIndex);
+ static void ReturnKey(int64 nIndex);
+ friend class CReserveKey;
+ friend std::vector<unsigned char> GetKeyFromKeyPool();
+ friend int64 GetOldestKeyPoolTime();
+};
+
+bool LoadWallet(bool& fFirstRunRet);
+void BackupWallet(const std::string& strDest);
+
+inline bool SetAddressBookName(const std::string& strAddress, const std::string& strName)
+{
+ return CWalletDB().WriteName(strAddress, strName);
+}
+
+class CReserveKey
+{
+protected:
+ int64 nIndex;
+ std::vector<unsigned char> vchPubKey;
+public:
+ CReserveKey()
+ {
+ nIndex = -1;
+ }
+
+ ~CReserveKey()
+ {
+ if (!fShutdown)
+ ReturnKey();
+ }
+
+ std::vector<unsigned char> GetReservedKey()
+ {
+ if (nIndex == -1)
+ {
+ CKeyPool keypool;
+ CWalletDB().ReserveKeyFromKeyPool(nIndex, keypool);
+ vchPubKey = keypool.vchPubKey;
+ }
+ assert(!vchPubKey.empty());
+ return vchPubKey;
+ }
+
+ void KeepKey()
+ {
+ if (nIndex != -1)
+ CWalletDB().KeepKey(nIndex);
+ nIndex = -1;
+ vchPubKey.clear();
+ }
+
+ void ReturnKey()
+ {
+ if (nIndex != -1)
+ CWalletDB::ReturnKey(nIndex);
+ nIndex = -1;
+ vchPubKey.clear();
+ }
+};
+
+#endif
diff --git a/core/include/headers.h b/core/include/headers.h
new file mode 100644
index 0000000000..d40c5ed0a9
--- /dev/null
+++ b/core/include/headers.h
@@ -0,0 +1,147 @@
+// 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.
+
+#ifdef _MSC_VER
+#pragma warning(disable:4786)
+#pragma warning(disable:4804)
+#pragma warning(disable:4805)
+#pragma warning(disable:4717)
+#endif
+#ifdef _WIN32_WINNT
+#undef _WIN32_WINNT
+#endif
+#define _WIN32_WINNT 0x0500
+#ifdef _WIN32_IE
+#undef _WIN32_IE
+#endif
+#define _WIN32_IE 0x0400
+#define WIN32_LEAN_AND_MEAN 1
+#define __STDC_LIMIT_MACROS // to enable UINT64_MAX from stdint.h
+#if (defined(__unix__) || defined(unix)) && !defined(USG)
+#include <sys/param.h> // to get BSD define
+#endif
+#ifdef __WXMAC_OSX__
+#ifndef BSD
+#define BSD 1
+#endif
+#endif
+#ifdef GUI
+#include <wx/wx.h>
+#include <wx/stdpaths.h>
+#include <wx/snglinst.h>
+#include <wx/utils.h>
+#include <wx/clipbrd.h>
+#include <wx/taskbar.h>
+#endif
+#include <openssl/buffer.h>
+#include <openssl/ecdsa.h>
+#include <openssl/evp.h>
+#include <openssl/rand.h>
+#include <openssl/sha.h>
+#include <openssl/ripemd.h>
+#include <db_cxx.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <math.h>
+#include <limits.h>
+#include <float.h>
+#include <assert.h>
+#include <memory>
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <vector>
+#include <list>
+#include <deque>
+#include <map>
+#include <set>
+#include <algorithm>
+#include <numeric>
+#include <boost/foreach.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/tuple/tuple.hpp>
+#include <boost/tuple/tuple_comparison.hpp>
+#include <boost/tuple/tuple_io.hpp>
+#include <boost/array.hpp>
+#include <boost/bind.hpp>
+#include <boost/function.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/filesystem/fstream.hpp>
+#include <boost/algorithm/string.hpp>
+#include <boost/thread.hpp>
+#include <boost/interprocess/sync/file_lock.hpp>
+#include <boost/interprocess/sync/interprocess_mutex.hpp>
+#include <boost/interprocess/sync/interprocess_recursive_mutex.hpp>
+#include <boost/date_time/gregorian/gregorian_types.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include <boost/config.hpp>
+#include <boost/program_options/detail/config_file.hpp>
+#include <boost/program_options/parsers.hpp>
+
+#ifdef __WXMSW__
+#include <windows.h>
+#include <winsock2.h>
+#include <mswsock.h>
+#include <shlobj.h>
+#include <shlwapi.h>
+#include <io.h>
+#include <process.h>
+#include <malloc.h>
+#else
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <errno.h>
+#include <net/if.h>
+#include <ifaddrs.h>
+#include <fcntl.h>
+#include <signal.h>
+#endif
+#ifdef BSD
+#include <netinet/in.h>
+#endif
+
+
+#pragma hdrstop
+
+#include "strlcpy.h"
+#include "serialize.h"
+#include "uint256.h"
+#include "util.h"
+#include "key.h"
+#include "bignum.h"
+#include "base58.h"
+#include "script.h"
+#include "db.h"
+#include "net.h"
+#include "irc.h"
+#include "main.h"
+#include "rpc.h"
+#ifdef GUI
+#include "uibase.h"
+#include "ui.h"
+#else
+#include "noui.h"
+#endif
+#include "init.h"
+
+#ifdef GUI
+#include "xpm/addressbook16.xpm"
+#include "xpm/addressbook20.xpm"
+#include "xpm/bitcoin16.xpm"
+#include "xpm/bitcoin20.xpm"
+#include "xpm/bitcoin32.xpm"
+#include "xpm/bitcoin48.xpm"
+#include "xpm/bitcoin80.xpm"
+#include "xpm/check.xpm"
+#include "xpm/send16.xpm"
+#include "xpm/send16noshadow.xpm"
+#include "xpm/send20.xpm"
+#include "xpm/about.xpm"
+#endif
diff --git a/core/include/init.h b/core/include/init.h
new file mode 100644
index 0000000000..61b2728576
--- /dev/null
+++ b/core/include/init.h
@@ -0,0 +1,11 @@
+// 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_INIT_H
+#define BITCOIN_INIT_H
+
+void Shutdown(void* parg);
+bool AppInit(int argc, char* argv[]);
+bool AppInit2(int argc, char* argv[]);
+
+#endif
diff --git a/core/include/irc.h b/core/include/irc.h
new file mode 100644
index 0000000000..18e53597f6
--- /dev/null
+++ b/core/include/irc.h
@@ -0,0 +1,13 @@
+// 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_IRC_H
+#define BITCOIN_IRC_H
+
+bool RecvLine(SOCKET hSocket, std::string& strLine);
+void ThreadIRCSeed(void* parg);
+
+extern int nGotIRCAddresses;
+extern bool fGotExternalIP;
+
+#endif
diff --git a/core/include/key.h b/core/include/key.h
index 390602e1ef..c973d6eb82 100644
--- a/core/include/key.h
+++ b/core/include/key.h
@@ -4,6 +4,10 @@
#ifndef BITCOIN_KEY_H
#define BITCOIN_KEY_H
+#include <openssl/ec.h>
+#include <openssl/ecdsa.h>
+#include <openssl/obj_mac.h>
+
// secp160k1
// const unsigned int PRIVATE_KEY_SIZE = 192;
// const unsigned int PUBLIC_KEY_SIZE = 41;
@@ -110,7 +114,7 @@ public:
return vchPrivKey;
}
- bool SetPubKey(const vector<unsigned char>& vchPubKey)
+ bool SetPubKey(const std::vector<unsigned char>& vchPubKey)
{
const unsigned char* pbegin = &vchPubKey[0];
if (!o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.size()))
@@ -119,19 +123,19 @@ public:
return true;
}
- vector<unsigned char> GetPubKey() const
+ std::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);
+ std::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)
+ bool Sign(uint256 hash, std::vector<unsigned char>& vchSig)
{
vchSig.clear();
unsigned char pchSig[10000];
@@ -143,7 +147,7 @@ public:
return true;
}
- bool Verify(uint256 hash, const vector<unsigned char>& vchSig)
+ bool Verify(uint256 hash, const std::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)
@@ -151,7 +155,7 @@ public:
return true;
}
- static bool Sign(const CPrivKey& vchPrivKey, uint256 hash, vector<unsigned char>& vchSig)
+ static bool Sign(const CPrivKey& vchPrivKey, uint256 hash, std::vector<unsigned char>& vchSig)
{
CKey key;
if (!key.SetPrivKey(vchPrivKey))
@@ -159,7 +163,7 @@ public:
return key.Sign(hash, vchSig);
}
- static bool Verify(const vector<unsigned char>& vchPubKey, uint256 hash, const vector<unsigned char>& vchSig)
+ static bool Verify(const std::vector<unsigned char>& vchPubKey, uint256 hash, const std::vector<unsigned char>& vchSig)
{
CKey key;
if (!key.SetPubKey(vchPubKey))
diff --git a/core/include/main.h b/core/include/main.h
index 7c9ace06c3..92b73fe5ad 100644
--- a/core/include/main.h
+++ b/core/include/main.h
@@ -7,6 +7,10 @@
#include "bignum.h"
#include "net.h"
#include "key.h"
+#include "db.h"
+#include "script.h"
+
+#include <list>
class COutPoint;
class CInPoint;
@@ -79,7 +83,7 @@ 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();
+std::vector<unsigned char> GenerateNewKey();
bool AddToWallet(const CWalletTx& wtxIn);
void WalletUpdateSpent(const COutPoint& prevout);
int ScanForWalletTransactions(CBlockIndex* pindexStart);
@@ -87,15 +91,15 @@ void ReacceptWalletTransactions();
bool LoadBlockIndex(bool fAllowNew=true);
void PrintBlockTree();
bool ProcessMessages(CNode* pfrom);
-bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv);
+bool ProcessMessage(CNode* pfrom, std::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(const std::vector<std::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);
+std::string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false);
+std::string SendMoneyToBitcoinAddress(std::string strAddress, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false);
void GenerateBitcoins(bool fGenerate);
void ThreadBitcoinMiner(void* parg);
CBlock* CreateNewBlock(CReserveKey& reservekey);
@@ -105,7 +109,7 @@ bool CheckWork(CBlock* pblock, CReserveKey& reservekey);
void BitcoinMiner();
bool CheckProofOfWork(uint256 hash, unsigned int nBits);
bool IsInitialBlockDownload();
-string GetWarnings(string strFor);
+std::string GetWarnings(std::string strFor);
@@ -153,7 +157,7 @@ public:
return !(a == b);
}
- string ToString() const
+ std::string ToString() const
{
if (IsNull())
return strprintf("null");
@@ -212,7 +216,7 @@ public:
return !(a == b);
}
- string ToString() const
+ std::string ToString() const
{
return strprintf("COutPoint(%s, %d)", hash.ToString().substr(0,10).c_str(), n);
}
@@ -281,9 +285,9 @@ public:
return !(a == b);
}
- string ToString() const
+ std::string ToString() const
{
- string str;
+ std::string str;
str += strprintf("CTxIn(");
str += prevout.ToString();
if (prevout.IsNull())
@@ -359,14 +363,14 @@ public:
int64 GetCredit() const
{
if (!MoneyRange(nValue))
- throw runtime_error("CTxOut::GetCredit() : value out of range");
+ throw std::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;
+ std::vector<unsigned char> vchPubKey;
if (ExtractPubKey(scriptPubKey, true, vchPubKey))
CRITICAL_BLOCK(cs_mapAddressBook)
if (!mapAddressBook.count(PubKeyToAddress(vchPubKey)))
@@ -377,7 +381,7 @@ public:
int64 GetChange() const
{
if (!MoneyRange(nValue))
- throw runtime_error("CTxOut::GetChange() : value out of range");
+ throw std::runtime_error("CTxOut::GetChange() : value out of range");
return (IsChange() ? nValue : 0);
}
@@ -392,7 +396,7 @@ public:
return !(a == b);
}
- string ToString() const
+ std::string ToString() const
{
if (scriptPubKey.size() < 6)
return "CTxOut(error)";
@@ -416,8 +420,8 @@ class CTransaction
{
public:
int nVersion;
- vector<CTxIn> vin;
- vector<CTxOut> vout;
+ std::vector<CTxIn> vin;
+ std::vector<CTxOut> vout;
unsigned int nLockTime;
@@ -464,7 +468,7 @@ public:
nBlockTime = GetAdjustedTime();
if ((int64)nLockTime < (nLockTime < 500000000 ? (int64)nBlockHeight : nBlockTime))
return true;
- foreach(const CTxIn& txin, vin)
+ BOOST_FOREACH(const CTxIn& txin, vin)
if (!txin.IsFinal())
return false;
return true;
@@ -507,19 +511,19 @@ public:
int GetSigOpCount() const
{
int n = 0;
- foreach(const CTxIn& txin, vin)
+ BOOST_FOREACH(const CTxIn& txin, vin)
n += txin.scriptSig.GetSigOpCount();
- foreach(const CTxOut& txout, vout)
+ BOOST_FOREACH(const CTxOut& txout, vout)
n += txout.scriptPubKey.GetSigOpCount();
return n;
}
bool IsStandard() const
{
- foreach(const CTxIn& txin, vin)
+ BOOST_FOREACH(const CTxIn& txin, vin)
if (!txin.scriptSig.IsPushOnly())
return error("nonstandard txin: %s", txin.scriptSig.ToString().c_str());
- foreach(const CTxOut& txout, vout)
+ BOOST_FOREACH(const CTxOut& txout, vout)
if (!::IsStandard(txout.scriptPubKey))
return error("nonstandard txout: %s", txout.scriptPubKey.ToString().c_str());
return true;
@@ -527,7 +531,7 @@ public:
bool IsMine() const
{
- foreach(const CTxOut& txout, vout)
+ BOOST_FOREACH(const CTxOut& txout, vout)
if (txout.IsMine())
return true;
return false;
@@ -541,11 +545,11 @@ public:
int64 GetDebit() const
{
int64 nDebit = 0;
- foreach(const CTxIn& txin, vin)
+ BOOST_FOREACH(const CTxIn& txin, vin)
{
nDebit += txin.GetDebit();
if (!MoneyRange(nDebit))
- throw runtime_error("CTransaction::GetDebit() : value out of range");
+ throw std::runtime_error("CTransaction::GetDebit() : value out of range");
}
return nDebit;
}
@@ -553,11 +557,11 @@ public:
int64 GetCredit() const
{
int64 nCredit = 0;
- foreach(const CTxOut& txout, vout)
+ BOOST_FOREACH(const CTxOut& txout, vout)
{
nCredit += txout.GetCredit();
if (!MoneyRange(nCredit))
- throw runtime_error("CTransaction::GetCredit() : value out of range");
+ throw std::runtime_error("CTransaction::GetCredit() : value out of range");
}
return nCredit;
}
@@ -567,11 +571,11 @@ public:
if (IsCoinBase())
return 0;
int64 nChange = 0;
- foreach(const CTxOut& txout, vout)
+ BOOST_FOREACH(const CTxOut& txout, vout)
{
nChange += txout.GetChange();
if (!MoneyRange(nChange))
- throw runtime_error("CTransaction::GetChange() : value out of range");
+ throw std::runtime_error("CTransaction::GetChange() : value out of range");
}
return nChange;
}
@@ -579,11 +583,11 @@ public:
int64 GetValueOut() const
{
int64 nValueOut = 0;
- foreach(const CTxOut& txout, vout)
+ BOOST_FOREACH(const CTxOut& txout, vout)
{
nValueOut += txout.nValue;
if (!MoneyRange(txout.nValue) || !MoneyRange(nValueOut))
- throw runtime_error("CTransaction::GetValueOut() : value out of range");
+ throw std::runtime_error("CTransaction::GetValueOut() : value out of range");
}
return nValueOut;
}
@@ -621,7 +625,7 @@ public:
// 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)
+ BOOST_FOREACH(const CTxOut& txout, vout)
if (txout.nValue < CENT)
nMinFee = MIN_TX_FEE;
@@ -674,9 +678,9 @@ public:
}
- string ToString() const
+ std::string ToString() const
{
- string str;
+ std::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,
@@ -700,7 +704,7 @@ public:
bool ReadFromDisk(CTxDB& txdb, COutPoint prevout);
bool ReadFromDisk(COutPoint prevout);
bool DisconnectInputs(CTxDB& txdb);
- bool ConnectInputs(CTxDB& txdb, map<uint256, CTxIndex>& mapTestPool, CDiskTxPos posThisTx,
+ bool ConnectInputs(CTxDB& txdb, std::map<uint256, CTxIndex>& mapTestPool, CDiskTxPos posThisTx,
CBlockIndex* pindexBlock, int64& nFees, bool fBlock, bool fMiner, int64 nMinFee=0);
bool ClientConnectInputs();
bool CheckTransaction() const;
@@ -727,7 +731,7 @@ class CMerkleTx : public CTransaction
{
public:
uint256 hashBlock;
- vector<uint256> vMerkleBranch;
+ std::vector<uint256> vMerkleBranch;
int nIndex;
// memory only
@@ -782,14 +786,14 @@ public:
class CWalletTx : public CMerkleTx
{
public:
- vector<CMerkleTx> vtxPrev;
- map<string, string> mapValue;
- vector<pair<string, string> > vOrderForm;
+ std::vector<CMerkleTx> vtxPrev;
+ std::map<std::string, std::string> mapValue;
+ std::vector<std::pair<std::string, std::string> > vOrderForm;
unsigned int fTimeReceivedIsTxTime;
unsigned int nTimeReceived; // time received by this node
char fFromMe;
- string strFromAccount;
- vector<char> vfSpent;
+ std::string strFromAccount;
+ std::vector<char> vfSpent;
// memory only
mutable char fDebitCached;
@@ -856,8 +860,8 @@ public:
{
pthis->mapValue["fromaccount"] = pthis->strFromAccount;
- string str;
- foreach(char f, vfSpent)
+ std::string str;
+ BOOST_FOREACH(char f, vfSpent)
{
str += (f ? '1' : '0');
if (f)
@@ -880,7 +884,7 @@ public:
pthis->strFromAccount = pthis->mapValue["fromaccount"];
if (mapValue.count("spent"))
- foreach(char c, pthis->mapValue["spent"])
+ BOOST_FOREACH(char c, pthis->mapValue["spent"])
pthis->vfSpent.push_back(c != '0');
else
pthis->vfSpent.assign(vout.size(), fSpent);
@@ -893,7 +897,7 @@ public:
// marks certain txout's as spent
// returns true if any update took place
- bool UpdateSpent(const vector<char>& vfNewSpent)
+ bool UpdateSpent(const std::vector<char>& vfNewSpent)
{
bool fReturn = false;
for (int i=0; i < vfNewSpent.size(); i++)
@@ -922,7 +926,7 @@ public:
void MarkSpent(unsigned int nOut)
{
if (nOut >= vout.size())
- throw runtime_error("CWalletTx::MarkSpent() : nOut out of range");
+ throw std::runtime_error("CWalletTx::MarkSpent() : nOut out of range");
vfSpent.resize(vout.size());
if (!vfSpent[nOut])
{
@@ -934,7 +938,7 @@ public:
bool IsSpent(unsigned int nOut) const
{
if (nOut >= vout.size())
- throw runtime_error("CWalletTx::IsSpent() : nOut out of range");
+ throw std::runtime_error("CWalletTx::IsSpent() : nOut out of range");
if (nOut >= vfSpent.size())
return false;
return (!!vfSpent[nOut]);
@@ -982,7 +986,7 @@ public:
const CTxOut &txout = vout[i];
nCredit += txout.GetCredit();
if (!MoneyRange(nCredit))
- throw runtime_error("CWalletTx::GetAvailableCredit() : value out of range");
+ throw std::runtime_error("CWalletTx::GetAvailableCredit() : value out of range");
}
}
@@ -1001,10 +1005,10 @@ public:
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 GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, std::list<std::pair<std::string /* address */, int64> >& listReceived,
+ std::list<std::pair<std::string /* address */, int64> >& listSent, int64& nFee, std::string& strSentAccount) const;
- void GetAccountAmounts(const string& strAccount, int64& nGenerated, int64& nReceived,
+ void GetAccountAmounts(const std::string& strAccount, int64& nGenerated, int64& nReceived,
int64& nSent, int64& nFee) const;
bool IsFromMe() const
@@ -1024,8 +1028,8 @@ public:
// 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;
+ std::map<uint256, const CMerkleTx*> mapPrev;
+ std::vector<const CMerkleTx*> vWorkQueue;
vWorkQueue.reserve(vtxPrev.size()+1);
vWorkQueue.push_back(this);
for (int i = 0; i < vWorkQueue.size(); i++)
@@ -1040,10 +1044,10 @@ public:
return false;
if (mapPrev.empty())
- foreach(const CMerkleTx& tx, vtxPrev)
+ BOOST_FOREACH(const CMerkleTx& tx, vtxPrev)
mapPrev[tx.GetHash()] = &tx;
- foreach(const CTxIn& txin, ptx->vin)
+ BOOST_FOREACH(const CTxIn& txin, ptx->vin)
{
if (!mapPrev.count(txin.prevout.hash))
return false;
@@ -1083,7 +1087,7 @@ class CTxIndex
{
public:
CDiskTxPos pos;
- vector<CDiskTxPos> vSpent;
+ std::vector<CDiskTxPos> vSpent;
CTxIndex()
{
@@ -1155,10 +1159,10 @@ public:
unsigned int nNonce;
// network and disk
- vector<CTransaction> vtx;
+ std::vector<CTransaction> vtx;
// memory only
- mutable vector<uint256> vMerkleTree;
+ mutable std::vector<uint256> vMerkleTree;
CBlock()
@@ -1213,7 +1217,7 @@ public:
int GetSigOpCount() const
{
int n = 0;
- foreach(const CTransaction& tx, vtx)
+ BOOST_FOREACH(const CTransaction& tx, vtx)
n += tx.GetSigOpCount();
return n;
}
@@ -1222,14 +1226,14 @@ public:
uint256 BuildMerkleTree() const
{
vMerkleTree.clear();
- foreach(const CTransaction& tx, vtx)
+ BOOST_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);
+ int i2 = std::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])));
}
@@ -1238,15 +1242,15 @@ public:
return (vMerkleTree.empty() ? 0 : vMerkleTree.back());
}
- vector<uint256> GetMerkleBranch(int nIndex) const
+ std::vector<uint256> GetMerkleBranch(int nIndex) const
{
if (vMerkleTree.empty())
BuildMerkleTree();
- vector<uint256> vMerkleBranch;
+ std::vector<uint256> vMerkleBranch;
int j = 0;
for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)
{
- int i = min(nIndex^1, nSize-1);
+ int i = std::min(nIndex^1, nSize-1);
vMerkleBranch.push_back(vMerkleTree[j+i]);
nIndex >>= 1;
j += nSize;
@@ -1254,11 +1258,11 @@ public:
return vMerkleBranch;
}
- static uint256 CheckMerkleBranch(uint256 hash, const vector<uint256>& vMerkleBranch, int nIndex)
+ static uint256 CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMerkleBranch, int nIndex)
{
if (nIndex == -1)
return 0;
- foreach(const uint256& otherside, vMerkleBranch)
+ BOOST_FOREACH(const uint256& otherside, vMerkleBranch)
{
if (nIndex & 1)
hash = Hash(BEGIN(otherside), END(otherside), BEGIN(hash), END(hash));
@@ -1489,7 +1493,7 @@ public:
for (int i = 0; i < nMedianTimeSpan && pindex; i++, pindex = pindex->pprev)
*(--pbegin) = pindex->GetBlockTime();
- sort(pbegin, pend);
+ std::sort(pbegin, pend);
return pbegin[(pend - pbegin)/2];
}
@@ -1507,7 +1511,7 @@ public:
- string ToString() const
+ std::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,
@@ -1576,9 +1580,9 @@ public:
}
- string ToString() const
+ std::string ToString() const
{
- string str = "CDiskBlockIndex(";
+ std::string str = "CDiskBlockIndex(";
str += CBlockIndex::ToString();
str += strprintf("\n hashBlock=%s, hashPrev=%s, hashNext=%s)",
GetBlockHash().ToString().c_str(),
@@ -1608,7 +1612,7 @@ public:
class CBlockLocator
{
protected:
- vector<uint256> vHave;
+ std::vector<uint256> vHave;
public:
CBlockLocator()
@@ -1622,7 +1626,7 @@ public:
explicit CBlockLocator(uint256 hashBlock)
{
- map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
+ std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
if (mi != mapBlockIndex.end())
Set((*mi).second);
}
@@ -1666,9 +1670,9 @@ public:
// Retrace how far back it was in the sender's branch
int nDistance = 0;
int nStep = 1;
- foreach(const uint256& hash, vHave)
+ BOOST_FOREACH(const uint256& hash, vHave)
{
- map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
+ std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
if (mi != mapBlockIndex.end())
{
CBlockIndex* pindex = (*mi).second;
@@ -1685,9 +1689,9 @@ public:
CBlockIndex* GetBlockIndex()
{
// Find the first block the caller has in the main chain
- foreach(const uint256& hash, vHave)
+ BOOST_FOREACH(const uint256& hash, vHave)
{
- map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
+ std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
if (mi != mapBlockIndex.end())
{
CBlockIndex* pindex = (*mi).second;
@@ -1701,9 +1705,9 @@ public:
uint256 GetBlockHash()
{
// Find the first block the caller has in the main chain
- foreach(const uint256& hash, vHave)
+ BOOST_FOREACH(const uint256& hash, vHave)
{
- map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
+ std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
if (mi != mapBlockIndex.end())
{
CBlockIndex* pindex = (*mi).second;
@@ -1737,7 +1741,7 @@ public:
CPrivKey vchPrivKey;
int64 nTimeCreated;
int64 nTimeExpires;
- string strComment;
+ std::string strComment;
//// todo: add something to note what created it (user, getnewaddress, change)
//// maybe should have a map<string, string> property map
@@ -1770,7 +1774,7 @@ public:
class CAccount
{
public:
- vector<unsigned char> vchPubKey;
+ std::vector<unsigned char> vchPubKey;
CAccount()
{
@@ -1799,11 +1803,11 @@ public:
class CAccountingEntry
{
public:
- string strAccount;
+ std::string strAccount;
int64 nCreditDebit;
int64 nTime;
- string strOtherAccount;
- string strComment;
+ std::string strOtherAccount;
+ std::string strComment;
CAccountingEntry()
{
@@ -1854,16 +1858,16 @@ public:
int64 nExpiration;
int nID;
int nCancel;
- set<int> setCancel;
+ std::set<int> setCancel;
int nMinVer; // lowest version inclusive
int nMaxVer; // highest version inclusive
- set<string> setSubVer; // empty matches all
+ std::set<std::string> setSubVer; // empty matches all
int nPriority;
// Actions
- string strComment;
- string strStatusBar;
- string strReserved;
+ std::string strComment;
+ std::string strStatusBar;
+ std::string strReserved;
IMPLEMENT_SERIALIZE
(
@@ -1902,13 +1906,13 @@ public:
strReserved.clear();
}
- string ToString() const
+ std::string ToString() const
{
- string strSetCancel;
- foreach(int n, setCancel)
+ std::string strSetCancel;
+ BOOST_FOREACH(int n, setCancel)
strSetCancel += strprintf("%d ", n);
- string strSetSubVer;
- foreach(string str, setSubVer)
+ std::string strSetSubVer;
+ BOOST_FOREACH(std::string str, setSubVer)
strSetSubVer += "\"" + str + "\" ";
return strprintf(
"CAlert(\n"
@@ -1948,8 +1952,8 @@ public:
class CAlert : public CUnsignedAlert
{
public:
- vector<unsigned char> vchMsg;
- vector<unsigned char> vchSig;
+ std::vector<unsigned char> vchMsg;
+ std::vector<unsigned char> vchSig;
CAlert()
{
@@ -1991,7 +1995,7 @@ public:
return (alert.nID <= nCancel || setCancel.count(alert.nID));
}
- bool AppliesTo(int nVersion, string strSubVerIn) const
+ bool AppliesTo(int nVersion, std::string strSubVerIn) const
{
return (IsInEffect() &&
nMinVer <= nVersion && nVersion <= nMaxVer &&
@@ -2047,12 +2051,12 @@ public:
-extern map<uint256, CTransaction> mapTransactions;
-extern map<uint256, CWalletTx> mapWallet;
-extern vector<uint256> vWalletUpdated;
+extern std::map<uint256, CTransaction> mapTransactions;
+extern std::map<uint256, CWalletTx> mapWallet;
+extern std::vector<uint256> vWalletUpdated;
extern CCriticalSection cs_mapWallet;
-extern map<vector<unsigned char>, CPrivKey> mapKeys;
-extern map<uint160, vector<unsigned char> > mapPubKeys;
+extern std::map<std::vector<unsigned char>, CPrivKey> mapKeys;
+extern std::map<uint160, std::vector<unsigned char> > mapPubKeys;
extern CCriticalSection cs_mapKeys;
extern CKey keyUser;
diff --git a/core/include/noui.h b/core/include/noui.h
new file mode 100644
index 0000000000..afb19526c1
--- /dev/null
+++ b/core/include/noui.h
@@ -0,0 +1,67 @@
+// Copyright (c) 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_NOUI_H
+#define BITCOIN_NOUI_H
+
+#include <string>
+
+typedef void wxWindow;
+#define wxYES 0x00000002
+#define wxOK 0x00000004
+#define wxNO 0x00000008
+#define wxYES_NO (wxYES|wxNO)
+#define wxCANCEL 0x00000010
+#define wxAPPLY 0x00000020
+#define wxCLOSE 0x00000040
+#define wxOK_DEFAULT 0x00000000
+#define wxYES_DEFAULT 0x00000000
+#define wxNO_DEFAULT 0x00000080
+#define wxCANCEL_DEFAULT 0x80000000
+#define wxICON_EXCLAMATION 0x00000100
+#define wxICON_HAND 0x00000200
+#define wxICON_WARNING wxICON_EXCLAMATION
+#define wxICON_ERROR wxICON_HAND
+#define wxICON_QUESTION 0x00000400
+#define wxICON_INFORMATION 0x00000800
+#define wxICON_STOP wxICON_HAND
+#define wxICON_ASTERISK wxICON_INFORMATION
+#define wxICON_MASK (0x00000100|0x00000200|0x00000400|0x00000800)
+#define wxFORWARD 0x00001000
+#define wxBACKWARD 0x00002000
+#define wxRESET 0x00004000
+#define wxHELP 0x00008000
+#define wxMORE 0x00010000
+#define wxSETUP 0x00020000
+
+inline int MyMessageBox(const std::string& message, const std::string& caption="Message", int style=wxOK, wxWindow* parent=NULL, int x=-1, int y=-1)
+{
+ printf("%s: %s\n", caption.c_str(), message.c_str());
+ fprintf(stderr, "%s: %s\n", caption.c_str(), message.c_str());
+ return 4;
+}
+#define wxMessageBox MyMessageBox
+
+inline int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style=wxOK, wxWindow* parent=NULL, int x=-1, int y=-1)
+{
+ return MyMessageBox(message, caption, style, parent, x, y);
+}
+
+inline bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption, wxWindow* parent)
+{
+ return true;
+}
+
+inline void CalledSetStatusBar(const std::string& strText, int nField)
+{
+}
+
+inline void UIThreadCall(boost::function0<void> fn)
+{
+}
+
+inline void MainFrameRepaint()
+{
+}
+
+#endif
diff --git a/core/include/rpc.h b/core/include/rpc.h
new file mode 100644
index 0000000000..48a7b8a8a6
--- /dev/null
+++ b/core/include/rpc.h
@@ -0,0 +1,6 @@
+// Copyright (c) 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.
+
+void ThreadRPCServer(void* parg);
+int CommandLineRPC(int argc, char *argv[]);
diff --git a/core/include/script.h b/core/include/script.h
new file mode 100644
index 0000000000..22a6020dce
--- /dev/null
+++ b/core/include/script.h
@@ -0,0 +1,718 @@
+// 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 H_BITCOIN_SCRIPT
+#define H_BITCOIN_SCRIPT
+
+#include "base58.h"
+
+#include <string>
+#include <vector>
+
+class CTransaction;
+
+enum
+{
+ SIGHASH_ALL = 1,
+ SIGHASH_NONE = 2,
+ SIGHASH_SINGLE = 3,
+ SIGHASH_ANYONECANPAY = 0x80,
+};
+
+
+
+enum opcodetype
+{
+ // push value
+ OP_0=0,
+ OP_FALSE=OP_0,
+ OP_PUSHDATA1=76,
+ OP_PUSHDATA2,
+ OP_PUSHDATA4,
+ OP_1NEGATE,
+ OP_RESERVED,
+ OP_1,
+ OP_TRUE=OP_1,
+ OP_2,
+ OP_3,
+ OP_4,
+ OP_5,
+ OP_6,
+ OP_7,
+ OP_8,
+ OP_9,
+ OP_10,
+ OP_11,
+ OP_12,
+ OP_13,
+ OP_14,
+ OP_15,
+ OP_16,
+
+ // control
+ OP_NOP,
+ OP_VER,
+ OP_IF,
+ OP_NOTIF,
+ OP_VERIF,
+ OP_VERNOTIF,
+ OP_ELSE,
+ OP_ENDIF,
+ OP_VERIFY,
+ OP_RETURN,
+
+ // stack ops
+ OP_TOALTSTACK,
+ OP_FROMALTSTACK,
+ OP_2DROP,
+ OP_2DUP,
+ OP_3DUP,
+ OP_2OVER,
+ OP_2ROT,
+ OP_2SWAP,
+ OP_IFDUP,
+ OP_DEPTH,
+ OP_DROP,
+ OP_DUP,
+ OP_NIP,
+ OP_OVER,
+ OP_PICK,
+ OP_ROLL,
+ OP_ROT,
+ OP_SWAP,
+ OP_TUCK,
+
+ // splice ops
+ OP_CAT,
+ OP_SUBSTR,
+ OP_LEFT,
+ OP_RIGHT,
+ OP_SIZE,
+
+ // bit logic
+ OP_INVERT,
+ OP_AND,
+ OP_OR,
+ OP_XOR,
+ OP_EQUAL,
+ OP_EQUALVERIFY,
+ OP_RESERVED1,
+ OP_RESERVED2,
+
+ // numeric
+ OP_1ADD,
+ OP_1SUB,
+ OP_2MUL,
+ OP_2DIV,
+ OP_NEGATE,
+ OP_ABS,
+ OP_NOT,
+ OP_0NOTEQUAL,
+
+ OP_ADD,
+ OP_SUB,
+ OP_MUL,
+ OP_DIV,
+ OP_MOD,
+ OP_LSHIFT,
+ OP_RSHIFT,
+
+ OP_BOOLAND,
+ OP_BOOLOR,
+ OP_NUMEQUAL,
+ OP_NUMEQUALVERIFY,
+ OP_NUMNOTEQUAL,
+ OP_LESSTHAN,
+ OP_GREATERTHAN,
+ OP_LESSTHANOREQUAL,
+ OP_GREATERTHANOREQUAL,
+ OP_MIN,
+ OP_MAX,
+
+ OP_WITHIN,
+
+ // crypto
+ OP_RIPEMD160,
+ OP_SHA1,
+ OP_SHA256,
+ OP_HASH160,
+ OP_HASH256,
+ OP_CODESEPARATOR,
+ OP_CHECKSIG,
+ OP_CHECKSIGVERIFY,
+ OP_CHECKMULTISIG,
+ OP_CHECKMULTISIGVERIFY,
+
+ // expansion
+ OP_NOP1,
+ OP_NOP2,
+ OP_NOP3,
+ OP_NOP4,
+ OP_NOP5,
+ OP_NOP6,
+ OP_NOP7,
+ OP_NOP8,
+ OP_NOP9,
+ OP_NOP10,
+
+
+
+ // template matching params
+ OP_PUBKEYHASH = 0xfd,
+ OP_PUBKEY = 0xfe,
+
+ OP_INVALIDOPCODE = 0xff,
+};
+
+
+
+
+
+
+
+
+inline const char* GetOpName(opcodetype opcode)
+{
+ switch (opcode)
+ {
+ // push value
+ case OP_0 : return "0";
+ case OP_PUSHDATA1 : return "OP_PUSHDATA1";
+ case OP_PUSHDATA2 : return "OP_PUSHDATA2";
+ case OP_PUSHDATA4 : return "OP_PUSHDATA4";
+ case OP_1NEGATE : return "-1";
+ case OP_RESERVED : return "OP_RESERVED";
+ case OP_1 : return "1";
+ case OP_2 : return "2";
+ case OP_3 : return "3";
+ case OP_4 : return "4";
+ case OP_5 : return "5";
+ case OP_6 : return "6";
+ case OP_7 : return "7";
+ case OP_8 : return "8";
+ case OP_9 : return "9";
+ case OP_10 : return "10";
+ case OP_11 : return "11";
+ case OP_12 : return "12";
+ case OP_13 : return "13";
+ case OP_14 : return "14";
+ case OP_15 : return "15";
+ case OP_16 : return "16";
+
+ // control
+ case OP_NOP : return "OP_NOP";
+ case OP_VER : return "OP_VER";
+ case OP_IF : return "OP_IF";
+ case OP_NOTIF : return "OP_NOTIF";
+ case OP_VERIF : return "OP_VERIF";
+ case OP_VERNOTIF : return "OP_VERNOTIF";
+ case OP_ELSE : return "OP_ELSE";
+ case OP_ENDIF : return "OP_ENDIF";
+ case OP_VERIFY : return "OP_VERIFY";
+ case OP_RETURN : return "OP_RETURN";
+
+ // stack ops
+ case OP_TOALTSTACK : return "OP_TOALTSTACK";
+ case OP_FROMALTSTACK : return "OP_FROMALTSTACK";
+ case OP_2DROP : return "OP_2DROP";
+ case OP_2DUP : return "OP_2DUP";
+ case OP_3DUP : return "OP_3DUP";
+ case OP_2OVER : return "OP_2OVER";
+ case OP_2ROT : return "OP_2ROT";
+ case OP_2SWAP : return "OP_2SWAP";
+ case OP_IFDUP : return "OP_IFDUP";
+ case OP_DEPTH : return "OP_DEPTH";
+ case OP_DROP : return "OP_DROP";
+ case OP_DUP : return "OP_DUP";
+ case OP_NIP : return "OP_NIP";
+ case OP_OVER : return "OP_OVER";
+ case OP_PICK : return "OP_PICK";
+ case OP_ROLL : return "OP_ROLL";
+ case OP_ROT : return "OP_ROT";
+ case OP_SWAP : return "OP_SWAP";
+ case OP_TUCK : return "OP_TUCK";
+
+ // splice ops
+ case OP_CAT : return "OP_CAT";
+ case OP_SUBSTR : return "OP_SUBSTR";
+ case OP_LEFT : return "OP_LEFT";
+ case OP_RIGHT : return "OP_RIGHT";
+ case OP_SIZE : return "OP_SIZE";
+
+ // bit logic
+ case OP_INVERT : return "OP_INVERT";
+ case OP_AND : return "OP_AND";
+ case OP_OR : return "OP_OR";
+ case OP_XOR : return "OP_XOR";
+ case OP_EQUAL : return "OP_EQUAL";
+ case OP_EQUALVERIFY : return "OP_EQUALVERIFY";
+ case OP_RESERVED1 : return "OP_RESERVED1";
+ case OP_RESERVED2 : return "OP_RESERVED2";
+
+ // numeric
+ case OP_1ADD : return "OP_1ADD";
+ case OP_1SUB : return "OP_1SUB";
+ case OP_2MUL : return "OP_2MUL";
+ case OP_2DIV : return "OP_2DIV";
+ case OP_NEGATE : return "OP_NEGATE";
+ case OP_ABS : return "OP_ABS";
+ case OP_NOT : return "OP_NOT";
+ case OP_0NOTEQUAL : return "OP_0NOTEQUAL";
+ case OP_ADD : return "OP_ADD";
+ case OP_SUB : return "OP_SUB";
+ case OP_MUL : return "OP_MUL";
+ case OP_DIV : return "OP_DIV";
+ case OP_MOD : return "OP_MOD";
+ case OP_LSHIFT : return "OP_LSHIFT";
+ case OP_RSHIFT : return "OP_RSHIFT";
+ case OP_BOOLAND : return "OP_BOOLAND";
+ case OP_BOOLOR : return "OP_BOOLOR";
+ case OP_NUMEQUAL : return "OP_NUMEQUAL";
+ case OP_NUMEQUALVERIFY : return "OP_NUMEQUALVERIFY";
+ case OP_NUMNOTEQUAL : return "OP_NUMNOTEQUAL";
+ case OP_LESSTHAN : return "OP_LESSTHAN";
+ case OP_GREATERTHAN : return "OP_GREATERTHAN";
+ case OP_LESSTHANOREQUAL : return "OP_LESSTHANOREQUAL";
+ case OP_GREATERTHANOREQUAL : return "OP_GREATERTHANOREQUAL";
+ case OP_MIN : return "OP_MIN";
+ case OP_MAX : return "OP_MAX";
+ case OP_WITHIN : return "OP_WITHIN";
+
+ // crypto
+ case OP_RIPEMD160 : return "OP_RIPEMD160";
+ case OP_SHA1 : return "OP_SHA1";
+ case OP_SHA256 : return "OP_SHA256";
+ case OP_HASH160 : return "OP_HASH160";
+ case OP_HASH256 : return "OP_HASH256";
+ case OP_CODESEPARATOR : return "OP_CODESEPARATOR";
+ case OP_CHECKSIG : return "OP_CHECKSIG";
+ case OP_CHECKSIGVERIFY : return "OP_CHECKSIGVERIFY";
+ case OP_CHECKMULTISIG : return "OP_CHECKMULTISIG";
+ case OP_CHECKMULTISIGVERIFY : return "OP_CHECKMULTISIGVERIFY";
+
+ // expanson
+ case OP_NOP1 : return "OP_NOP1";
+ case OP_NOP2 : return "OP_NOP2";
+ case OP_NOP3 : return "OP_NOP3";
+ case OP_NOP4 : return "OP_NOP4";
+ case OP_NOP5 : return "OP_NOP5";
+ case OP_NOP6 : return "OP_NOP6";
+ case OP_NOP7 : return "OP_NOP7";
+ case OP_NOP8 : return "OP_NOP8";
+ case OP_NOP9 : return "OP_NOP9";
+ case OP_NOP10 : return "OP_NOP10";
+
+
+
+ // template matching params
+ case OP_PUBKEYHASH : return "OP_PUBKEYHASH";
+ case OP_PUBKEY : return "OP_PUBKEY";
+
+ case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE";
+ default:
+ return "OP_UNKNOWN";
+ }
+};
+
+
+
+
+inline std::string ValueString(const std::vector<unsigned char>& vch)
+{
+ if (vch.size() <= 4)
+ return strprintf("%d", CBigNum(vch).getint());
+ else
+ return HexStr(vch);
+}
+
+inline std::string StackString(const std::vector<std::vector<unsigned char> >& vStack)
+{
+ std::string str;
+ BOOST_FOREACH(const std::vector<unsigned char>& vch, vStack)
+ {
+ if (!str.empty())
+ str += " ";
+ str += ValueString(vch);
+ }
+ return str;
+}
+
+
+
+
+
+
+
+
+
+class CScript : public std::vector<unsigned char>
+{
+protected:
+ CScript& push_int64(int64 n)
+ {
+ if (n == -1 || (n >= 1 && n <= 16))
+ {
+ push_back(n + (OP_1 - 1));
+ }
+ else
+ {
+ CBigNum bn(n);
+ *this << bn.getvch();
+ }
+ return *this;
+ }
+
+ CScript& push_uint64(uint64 n)
+ {
+ if (n >= 1 && n <= 16)
+ {
+ push_back(n + (OP_1 - 1));
+ }
+ else
+ {
+ CBigNum bn(n);
+ *this << bn.getvch();
+ }
+ return *this;
+ }
+
+public:
+ CScript() { }
+ CScript(const CScript& b) : std::vector<unsigned char>(b.begin(), b.end()) { }
+ CScript(const_iterator pbegin, const_iterator pend) : std::vector<unsigned char>(pbegin, pend) { }
+#ifndef _MSC_VER
+ CScript(const unsigned char* pbegin, const unsigned char* pend) : std::vector<unsigned char>(pbegin, pend) { }
+#endif
+
+ CScript& operator+=(const CScript& b)
+ {
+ insert(end(), b.begin(), b.end());
+ return *this;
+ }
+
+ friend CScript operator+(const CScript& a, const CScript& b)
+ {
+ CScript ret = a;
+ ret += b;
+ return ret;
+ }
+
+
+ explicit CScript(char b) { operator<<(b); }
+ explicit CScript(short b) { operator<<(b); }
+ explicit CScript(int b) { operator<<(b); }
+ explicit CScript(long b) { operator<<(b); }
+ explicit CScript(int64 b) { operator<<(b); }
+ explicit CScript(unsigned char b) { operator<<(b); }
+ explicit CScript(unsigned int b) { operator<<(b); }
+ explicit CScript(unsigned short b) { operator<<(b); }
+ explicit CScript(unsigned long b) { operator<<(b); }
+ explicit CScript(uint64 b) { operator<<(b); }
+
+ explicit CScript(opcodetype b) { operator<<(b); }
+ explicit CScript(const uint256& b) { operator<<(b); }
+ explicit CScript(const CBigNum& b) { operator<<(b); }
+ explicit CScript(const std::vector<unsigned char>& b) { operator<<(b); }
+
+
+ CScript& operator<<(char b) { return push_int64(b); }
+ CScript& operator<<(short b) { return push_int64(b); }
+ CScript& operator<<(int b) { return push_int64(b); }
+ CScript& operator<<(long b) { return push_int64(b); }
+ CScript& operator<<(int64 b) { return push_int64(b); }
+ CScript& operator<<(unsigned char b) { return push_uint64(b); }
+ CScript& operator<<(unsigned int b) { return push_uint64(b); }
+ CScript& operator<<(unsigned short b) { return push_uint64(b); }
+ CScript& operator<<(unsigned long b) { return push_uint64(b); }
+ CScript& operator<<(uint64 b) { return push_uint64(b); }
+
+ CScript& operator<<(opcodetype opcode)
+ {
+ if (opcode < 0 || opcode > 0xff)
+ throw std::runtime_error("CScript::operator<<() : invalid opcode");
+ insert(end(), (unsigned char)opcode);
+ return *this;
+ }
+
+ CScript& operator<<(const uint160& b)
+ {
+ insert(end(), sizeof(b));
+ insert(end(), (unsigned char*)&b, (unsigned char*)&b + sizeof(b));
+ return *this;
+ }
+
+ CScript& operator<<(const uint256& b)
+ {
+ insert(end(), sizeof(b));
+ insert(end(), (unsigned char*)&b, (unsigned char*)&b + sizeof(b));
+ return *this;
+ }
+
+ CScript& operator<<(const CBigNum& b)
+ {
+ *this << b.getvch();
+ return *this;
+ }
+
+ CScript& operator<<(const std::vector<unsigned char>& b)
+ {
+ if (b.size() < OP_PUSHDATA1)
+ {
+ insert(end(), (unsigned char)b.size());
+ }
+ else if (b.size() <= 0xff)
+ {
+ insert(end(), OP_PUSHDATA1);
+ insert(end(), (unsigned char)b.size());
+ }
+ else if (b.size() <= 0xffff)
+ {
+ insert(end(), OP_PUSHDATA2);
+ unsigned short nSize = b.size();
+ insert(end(), (unsigned char*)&nSize, (unsigned char*)&nSize + sizeof(nSize));
+ }
+ else
+ {
+ insert(end(), OP_PUSHDATA4);
+ unsigned int nSize = b.size();
+ insert(end(), (unsigned char*)&nSize, (unsigned char*)&nSize + sizeof(nSize));
+ }
+ insert(end(), b.begin(), b.end());
+ return *this;
+ }
+
+ CScript& operator<<(const CScript& b)
+ {
+ // I'm not sure if this should push the script or concatenate scripts.
+ // If there's ever a use for pushing a script onto a script, delete this member fn
+ assert(("warning: pushing a CScript onto a CScript with << is probably not intended, use + to concatenate", false));
+ return *this;
+ }
+
+
+ bool GetOp(iterator& pc, opcodetype& opcodeRet, std::vector<unsigned char>& vchRet)
+ {
+ // Wrapper so it can be called with either iterator or const_iterator
+ const_iterator pc2 = pc;
+ bool fRet = GetOp2(pc2, opcodeRet, &vchRet);
+ pc = begin() + (pc2 - begin());
+ return fRet;
+ }
+
+ bool GetOp(iterator& pc, opcodetype& opcodeRet)
+ {
+ const_iterator pc2 = pc;
+ bool fRet = GetOp2(pc2, opcodeRet, NULL);
+ pc = begin() + (pc2 - begin());
+ return fRet;
+ }
+
+ bool GetOp(const_iterator& pc, opcodetype& opcodeRet, std::vector<unsigned char>& vchRet) const
+ {
+ return GetOp2(pc, opcodeRet, &vchRet);
+ }
+
+ bool GetOp(const_iterator& pc, opcodetype& opcodeRet) const
+ {
+ return GetOp2(pc, opcodeRet, NULL);
+ }
+
+ bool GetOp2(const_iterator& pc, opcodetype& opcodeRet, std::vector<unsigned char>* pvchRet) const
+ {
+ opcodeRet = OP_INVALIDOPCODE;
+ if (pvchRet)
+ pvchRet->clear();
+ if (pc >= end())
+ return false;
+
+ // Read instruction
+ if (end() - pc < 1)
+ return false;
+ unsigned int opcode = *pc++;
+
+ // Immediate operand
+ if (opcode <= OP_PUSHDATA4)
+ {
+ unsigned int nSize;
+ if (opcode < OP_PUSHDATA1)
+ {
+ nSize = opcode;
+ }
+ else if (opcode == OP_PUSHDATA1)
+ {
+ if (end() - pc < 1)
+ return false;
+ nSize = *pc++;
+ }
+ else if (opcode == OP_PUSHDATA2)
+ {
+ if (end() - pc < 2)
+ return false;
+ nSize = 0;
+ memcpy(&nSize, &pc[0], 2);
+ pc += 2;
+ }
+ else if (opcode == OP_PUSHDATA4)
+ {
+ if (end() - pc < 4)
+ return false;
+ memcpy(&nSize, &pc[0], 4);
+ pc += 4;
+ }
+ if (end() - pc < nSize)
+ return false;
+ if (pvchRet)
+ pvchRet->assign(pc, pc + nSize);
+ pc += nSize;
+ }
+
+ opcodeRet = (opcodetype)opcode;
+ return true;
+ }
+
+
+ void FindAndDelete(const CScript& b)
+ {
+ if (b.empty())
+ return;
+ iterator pc = begin();
+ opcodetype opcode;
+ do
+ {
+ while (end() - pc >= b.size() && memcmp(&pc[0], &b[0], b.size()) == 0)
+ erase(pc, pc + b.size());
+ }
+ while (GetOp(pc, opcode));
+ }
+
+
+ int GetSigOpCount() const
+ {
+ int n = 0;
+ const_iterator pc = begin();
+ while (pc < end())
+ {
+ opcodetype opcode;
+ if (!GetOp(pc, opcode))
+ break;
+ if (opcode == OP_CHECKSIG || opcode == OP_CHECKSIGVERIFY)
+ n++;
+ else if (opcode == OP_CHECKMULTISIG || opcode == OP_CHECKMULTISIGVERIFY)
+ n += 20;
+ }
+ return n;
+ }
+
+
+ bool IsPushOnly() const
+ {
+ if (size() > 200)
+ return false;
+ const_iterator pc = begin();
+ while (pc < end())
+ {
+ opcodetype opcode;
+ if (!GetOp(pc, opcode))
+ return false;
+ if (opcode > OP_16)
+ return false;
+ }
+ return true;
+ }
+
+
+ uint160 GetBitcoinAddressHash160() const
+ {
+ opcodetype opcode;
+ std::vector<unsigned char> vch;
+ CScript::const_iterator pc = begin();
+ if (!GetOp(pc, opcode, vch) || opcode != OP_DUP) return 0;
+ if (!GetOp(pc, opcode, vch) || opcode != OP_HASH160) return 0;
+ if (!GetOp(pc, opcode, vch) || vch.size() != sizeof(uint160)) return 0;
+ uint160 hash160 = uint160(vch);
+ if (!GetOp(pc, opcode, vch) || opcode != OP_EQUALVERIFY) return 0;
+ if (!GetOp(pc, opcode, vch) || opcode != OP_CHECKSIG) return 0;
+ if (pc != end()) return 0;
+ return hash160;
+ }
+
+ std::string GetBitcoinAddress() const
+ {
+ uint160 hash160 = GetBitcoinAddressHash160();
+ if (hash160 == 0)
+ return "";
+ return Hash160ToAddress(hash160);
+ }
+
+ void SetBitcoinAddress(const uint160& hash160)
+ {
+ this->clear();
+ *this << OP_DUP << OP_HASH160 << hash160 << OP_EQUALVERIFY << OP_CHECKSIG;
+ }
+
+ void SetBitcoinAddress(const std::vector<unsigned char>& vchPubKey)
+ {
+ SetBitcoinAddress(Hash160(vchPubKey));
+ }
+
+ bool SetBitcoinAddress(const std::string& strAddress)
+ {
+ this->clear();
+ uint160 hash160;
+ if (!AddressToHash160(strAddress, hash160))
+ return false;
+ SetBitcoinAddress(hash160);
+ return true;
+ }
+
+
+ void PrintHex() const
+ {
+ printf("CScript(%s)\n", HexStr(begin(), end(), true).c_str());
+ }
+
+ std::string ToString() const
+ {
+ std::string str;
+ opcodetype opcode;
+ std::vector<unsigned char> vch;
+ const_iterator pc = begin();
+ while (pc < end())
+ {
+ if (!str.empty())
+ str += " ";
+ if (!GetOp(pc, opcode, vch))
+ {
+ str += "[error]";
+ return str;
+ }
+ if (0 <= opcode && opcode <= OP_PUSHDATA4)
+ str += ValueString(vch);
+ else
+ str += GetOpName(opcode);
+ }
+ return str;
+ }
+
+ void print() const
+ {
+ printf("%s\n", ToString().c_str());
+ }
+};
+
+
+
+
+
+
+
+
+uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
+bool IsStandard(const CScript& scriptPubKey);
+bool IsMine(const CScript& scriptPubKey);
+bool ExtractPubKey(const CScript& scriptPubKey, bool fMineOnly, std::vector<unsigned char>& vchPubKeyRet);
+bool ExtractHash160(const CScript& scriptPubKey, uint160& hash160Ret);
+bool SignSignature(const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL, CScript scriptPrereq=CScript());
+bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsigned int nIn, int nHashType=0);
+
+#endif
diff --git a/core/src/db.cpp b/core/src/db.cpp
new file mode 100644
index 0000000000..52c0f5b4c3
--- /dev/null
+++ b/core/src/db.cpp
@@ -0,0 +1,1026 @@
+// 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.
+
+#include "headers.h"
+
+using namespace std;
+using namespace boost;
+
+void ThreadFlushWalletDB(void* parg);
+
+
+unsigned int nWalletDBUpdated;
+uint64 nAccountingEntryNumber = 0;
+
+
+
+//
+// CDB
+//
+
+static CCriticalSection cs_db;
+static bool fDbEnvInit = false;
+DbEnv dbenv(0);
+static map<string, int> mapFileUseCount;
+static map<string, Db*> mapDb;
+
+class CDBInit
+{
+public:
+ CDBInit()
+ {
+ }
+ ~CDBInit()
+ {
+ if (fDbEnvInit)
+ {
+ dbenv.close(0);
+ fDbEnvInit = false;
+ }
+ }
+}
+instance_of_cdbinit;
+
+
+CDB::CDB(const char* pszFile, const char* pszMode) : pdb(NULL)
+{
+ int ret;
+ if (pszFile == NULL)
+ return;
+
+ fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w'));
+ bool fCreate = strchr(pszMode, 'c');
+ unsigned int nFlags = DB_THREAD;
+ if (fCreate)
+ nFlags |= DB_CREATE;
+
+ CRITICAL_BLOCK(cs_db)
+ {
+ if (!fDbEnvInit)
+ {
+ if (fShutdown)
+ return;
+ string strDataDir = GetDataDir();
+ string strLogDir = strDataDir + "/database";
+ filesystem::create_directory(strLogDir.c_str());
+ string strErrorFile = strDataDir + "/db.log";
+ printf("dbenv.open strLogDir=%s strErrorFile=%s\n", strLogDir.c_str(), strErrorFile.c_str());
+
+ dbenv.set_lg_dir(strLogDir.c_str());
+ dbenv.set_lg_max(10000000);
+ dbenv.set_lk_max_locks(10000);
+ dbenv.set_lk_max_objects(10000);
+ dbenv.set_errfile(fopen(strErrorFile.c_str(), "a")); /// debug
+ dbenv.set_flags(DB_AUTO_COMMIT, 1);
+ ret = dbenv.open(strDataDir.c_str(),
+ DB_CREATE |
+ DB_INIT_LOCK |
+ DB_INIT_LOG |
+ DB_INIT_MPOOL |
+ DB_INIT_TXN |
+ DB_THREAD |
+ DB_RECOVER,
+ S_IRUSR | S_IWUSR);
+ if (ret > 0)
+ throw runtime_error(strprintf("CDB() : error %d opening database environment", ret));
+ fDbEnvInit = true;
+ }
+
+ strFile = pszFile;
+ ++mapFileUseCount[strFile];
+ pdb = mapDb[strFile];
+ if (pdb == NULL)
+ {
+ pdb = new Db(&dbenv, 0);
+
+ ret = pdb->open(NULL, // Txn pointer
+ pszFile, // Filename
+ "main", // Logical db name
+ DB_BTREE, // Database type
+ nFlags, // Flags
+ 0);
+
+ if (ret > 0)
+ {
+ delete pdb;
+ pdb = NULL;
+ CRITICAL_BLOCK(cs_db)
+ --mapFileUseCount[strFile];
+ strFile = "";
+ throw runtime_error(strprintf("CDB() : can't open database file %s, error %d", pszFile, ret));
+ }
+
+ if (fCreate && !Exists(string("version")))
+ {
+ bool fTmp = fReadOnly;
+ fReadOnly = false;
+ WriteVersion(VERSION);
+ fReadOnly = fTmp;
+ }
+
+ mapDb[strFile] = pdb;
+ }
+ }
+}
+
+void CDB::Close()
+{
+ if (!pdb)
+ return;
+ if (!vTxn.empty())
+ vTxn.front()->abort();
+ vTxn.clear();
+ pdb = NULL;
+
+ // Flush database activity from memory pool to disk log
+ unsigned int nMinutes = 0;
+ if (fReadOnly)
+ nMinutes = 1;
+ if (strFile == "addr.dat")
+ nMinutes = 2;
+ if (strFile == "blkindex.dat" && IsInitialBlockDownload() && nBestHeight % 500 != 0)
+ nMinutes = 1;
+ dbenv.txn_checkpoint(0, nMinutes, 0);
+
+ CRITICAL_BLOCK(cs_db)
+ --mapFileUseCount[strFile];
+}
+
+void CloseDb(const string& strFile)
+{
+ CRITICAL_BLOCK(cs_db)
+ {
+ if (mapDb[strFile] != NULL)
+ {
+ // Close the database handle
+ Db* pdb = mapDb[strFile];
+ pdb->close(0);
+ delete pdb;
+ mapDb[strFile] = NULL;
+ }
+ }
+}
+
+void DBFlush(bool fShutdown)
+{
+ // Flush log data to the actual data file
+ // on all files that are not in use
+ printf("DBFlush(%s)%s\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " db not started");
+ if (!fDbEnvInit)
+ return;
+ CRITICAL_BLOCK(cs_db)
+ {
+ map<string, int>::iterator mi = mapFileUseCount.begin();
+ while (mi != mapFileUseCount.end())
+ {
+ string strFile = (*mi).first;
+ int nRefCount = (*mi).second;
+ printf("%s refcount=%d\n", strFile.c_str(), nRefCount);
+ if (nRefCount == 0)
+ {
+ // Move log data to the dat file
+ CloseDb(strFile);
+ dbenv.txn_checkpoint(0, 0, 0);
+ printf("%s flush\n", strFile.c_str());
+ dbenv.lsn_reset(strFile.c_str(), 0);
+ mapFileUseCount.erase(mi++);
+ }
+ else
+ mi++;
+ }
+ if (fShutdown)
+ {
+ char** listp;
+ if (mapFileUseCount.empty())
+ dbenv.log_archive(&listp, DB_ARCH_REMOVE);
+ dbenv.close(0);
+ fDbEnvInit = false;
+ }
+ }
+}
+
+
+
+
+
+
+//
+// CTxDB
+//
+
+bool CTxDB::ReadTxIndex(uint256 hash, CTxIndex& txindex)
+{
+ assert(!fClient);
+ txindex.SetNull();
+ return Read(make_pair(string("tx"), hash), txindex);
+}
+
+bool CTxDB::UpdateTxIndex(uint256 hash, const CTxIndex& txindex)
+{
+ assert(!fClient);
+ return Write(make_pair(string("tx"), hash), txindex);
+}
+
+bool CTxDB::AddTxIndex(const CTransaction& tx, const CDiskTxPos& pos, int nHeight)
+{
+ assert(!fClient);
+
+ // Add to tx index
+ uint256 hash = tx.GetHash();
+ CTxIndex txindex(pos, tx.vout.size());
+ return Write(make_pair(string("tx"), hash), txindex);
+}
+
+bool CTxDB::EraseTxIndex(const CTransaction& tx)
+{
+ assert(!fClient);
+ uint256 hash = tx.GetHash();
+
+ return Erase(make_pair(string("tx"), hash));
+}
+
+bool CTxDB::ContainsTx(uint256 hash)
+{
+ assert(!fClient);
+ return Exists(make_pair(string("tx"), hash));
+}
+
+bool CTxDB::ReadOwnerTxes(uint160 hash160, int nMinHeight, vector<CTransaction>& vtx)
+{
+ assert(!fClient);
+ vtx.clear();
+
+ // Get cursor
+ Dbc* pcursor = GetCursor();
+ if (!pcursor)
+ return false;
+
+ unsigned int fFlags = DB_SET_RANGE;
+ loop
+ {
+ // Read next record
+ CDataStream ssKey;
+ if (fFlags == DB_SET_RANGE)
+ ssKey << string("owner") << hash160 << CDiskTxPos(0, 0, 0);
+ CDataStream ssValue;
+ int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
+ fFlags = DB_NEXT;
+ if (ret == DB_NOTFOUND)
+ break;
+ else if (ret != 0)
+ {
+ pcursor->close();
+ return false;
+ }
+
+ // Unserialize
+ string strType;
+ uint160 hashItem;
+ CDiskTxPos pos;
+ ssKey >> strType >> hashItem >> pos;
+ int nItemHeight;
+ ssValue >> nItemHeight;
+
+ // Read transaction
+ if (strType != "owner" || hashItem != hash160)
+ break;
+ if (nItemHeight >= nMinHeight)
+ {
+ vtx.resize(vtx.size()+1);
+ if (!vtx.back().ReadFromDisk(pos))
+ {
+ pcursor->close();
+ return false;
+ }
+ }
+ }
+
+ pcursor->close();
+ return true;
+}
+
+bool CTxDB::ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex)
+{
+ assert(!fClient);
+ tx.SetNull();
+ if (!ReadTxIndex(hash, txindex))
+ return false;
+ return (tx.ReadFromDisk(txindex.pos));
+}
+
+bool CTxDB::ReadDiskTx(uint256 hash, CTransaction& tx)
+{
+ CTxIndex txindex;
+ return ReadDiskTx(hash, tx, txindex);
+}
+
+bool CTxDB::ReadDiskTx(COutPoint outpoint, CTransaction& tx, CTxIndex& txindex)
+{
+ return ReadDiskTx(outpoint.hash, tx, txindex);
+}
+
+bool CTxDB::ReadDiskTx(COutPoint outpoint, CTransaction& tx)
+{
+ CTxIndex txindex;
+ return ReadDiskTx(outpoint.hash, tx, txindex);
+}
+
+bool CTxDB::WriteBlockIndex(const CDiskBlockIndex& blockindex)
+{
+ return Write(make_pair(string("blockindex"), blockindex.GetBlockHash()), blockindex);
+}
+
+bool CTxDB::EraseBlockIndex(uint256 hash)
+{
+ return Erase(make_pair(string("blockindex"), hash));
+}
+
+bool CTxDB::ReadHashBestChain(uint256& hashBestChain)
+{
+ return Read(string("hashBestChain"), hashBestChain);
+}
+
+bool CTxDB::WriteHashBestChain(uint256 hashBestChain)
+{
+ return Write(string("hashBestChain"), hashBestChain);
+}
+
+bool CTxDB::ReadBestInvalidWork(CBigNum& bnBestInvalidWork)
+{
+ return Read(string("bnBestInvalidWork"), bnBestInvalidWork);
+}
+
+bool CTxDB::WriteBestInvalidWork(CBigNum bnBestInvalidWork)
+{
+ return Write(string("bnBestInvalidWork"), bnBestInvalidWork);
+}
+
+CBlockIndex* InsertBlockIndex(uint256 hash)
+{
+ if (hash == 0)
+ return NULL;
+
+ // Return existing
+ map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
+ if (mi != mapBlockIndex.end())
+ return (*mi).second;
+
+ // Create new
+ CBlockIndex* pindexNew = new CBlockIndex();
+ if (!pindexNew)
+ throw runtime_error("LoadBlockIndex() : new CBlockIndex failed");
+ mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first;
+ pindexNew->phashBlock = &((*mi).first);
+
+ return pindexNew;
+}
+
+bool CTxDB::LoadBlockIndex()
+{
+ // Get database cursor
+ Dbc* pcursor = GetCursor();
+ if (!pcursor)
+ return false;
+
+ // Load mapBlockIndex
+ unsigned int fFlags = DB_SET_RANGE;
+ loop
+ {
+ // Read next record
+ CDataStream ssKey;
+ if (fFlags == DB_SET_RANGE)
+ ssKey << make_pair(string("blockindex"), uint256(0));
+ CDataStream ssValue;
+ int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
+ fFlags = DB_NEXT;
+ if (ret == DB_NOTFOUND)
+ break;
+ else if (ret != 0)
+ return false;
+
+ // Unserialize
+ string strType;
+ ssKey >> strType;
+ if (strType == "blockindex")
+ {
+ CDiskBlockIndex diskindex;
+ ssValue >> diskindex;
+
+ // Construct block index object
+ CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash());
+ pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev);
+ pindexNew->pnext = InsertBlockIndex(diskindex.hashNext);
+ pindexNew->nFile = diskindex.nFile;
+ pindexNew->nBlockPos = diskindex.nBlockPos;
+ pindexNew->nHeight = diskindex.nHeight;
+ pindexNew->nVersion = diskindex.nVersion;
+ pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
+ pindexNew->nTime = diskindex.nTime;
+ pindexNew->nBits = diskindex.nBits;
+ pindexNew->nNonce = diskindex.nNonce;
+
+ // Watch for genesis block
+ if (pindexGenesisBlock == NULL && diskindex.GetBlockHash() == hashGenesisBlock)
+ pindexGenesisBlock = pindexNew;
+
+ if (!pindexNew->CheckIndex())
+ return error("LoadBlockIndex() : CheckIndex failed at %d", pindexNew->nHeight);
+ }
+ else
+ {
+ break;
+ }
+ }
+ pcursor->close();
+
+ // Calculate bnChainWork
+ vector<pair<int, CBlockIndex*> > vSortedByHeight;
+ vSortedByHeight.reserve(mapBlockIndex.size());
+ BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex)
+ {
+ CBlockIndex* pindex = item.second;
+ vSortedByHeight.push_back(make_pair(pindex->nHeight, pindex));
+ }
+ sort(vSortedByHeight.begin(), vSortedByHeight.end());
+ BOOST_FOREACH(const PAIRTYPE(int, CBlockIndex*)& item, vSortedByHeight)
+ {
+ CBlockIndex* pindex = item.second;
+ pindex->bnChainWork = (pindex->pprev ? pindex->pprev->bnChainWork : 0) + pindex->GetBlockWork();
+ }
+
+ // Load hashBestChain pointer to end of best chain
+ if (!ReadHashBestChain(hashBestChain))
+ {
+ if (pindexGenesisBlock == NULL)
+ return true;
+ return error("CTxDB::LoadBlockIndex() : hashBestChain not loaded");
+ }
+ if (!mapBlockIndex.count(hashBestChain))
+ return error("CTxDB::LoadBlockIndex() : hashBestChain not found in the block index");
+ pindexBest = mapBlockIndex[hashBestChain];
+ nBestHeight = pindexBest->nHeight;
+ bnBestChainWork = pindexBest->bnChainWork;
+ printf("LoadBlockIndex(): hashBestChain=%s height=%d\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight);
+
+ // Load bnBestInvalidWork, OK if it doesn't exist
+ ReadBestInvalidWork(bnBestInvalidWork);
+
+ // Verify blocks in the best chain
+ CBlockIndex* pindexFork = NULL;
+ for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev)
+ {
+ if (pindex->nHeight < nBestHeight-2500 && !mapArgs.count("-checkblocks"))
+ break;
+ CBlock block;
+ if (!block.ReadFromDisk(pindex))
+ return error("LoadBlockIndex() : block.ReadFromDisk failed");
+ if (!block.CheckBlock())
+ {
+ printf("LoadBlockIndex() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
+ pindexFork = pindex->pprev;
+ }
+ }
+ if (pindexFork)
+ {
+ // Reorg back to the fork
+ printf("LoadBlockIndex() : *** moving best chain pointer back to block %d\n", pindexFork->nHeight);
+ CBlock block;
+ if (!block.ReadFromDisk(pindexFork))
+ return error("LoadBlockIndex() : block.ReadFromDisk failed");
+ CTxDB txdb;
+ block.SetBestChain(txdb, pindexFork);
+ }
+
+ return true;
+}
+
+
+
+
+
+//
+// CAddrDB
+//
+
+bool CAddrDB::WriteAddress(const CAddress& addr)
+{
+ return Write(make_pair(string("addr"), addr.GetKey()), addr);
+}
+
+bool CAddrDB::EraseAddress(const CAddress& addr)
+{
+ return Erase(make_pair(string("addr"), addr.GetKey()));
+}
+
+bool CAddrDB::LoadAddresses()
+{
+ CRITICAL_BLOCK(cs_mapAddresses)
+ {
+ // Load user provided addresses
+ CAutoFile filein = fopen((GetDataDir() + "/addr.txt").c_str(), "rt");
+ if (filein)
+ {
+ try
+ {
+ char psz[1000];
+ while (fgets(psz, sizeof(psz), filein))
+ {
+ CAddress addr(psz, NODE_NETWORK);
+ addr.nTime = 0; // so it won't relay unless successfully connected
+ if (addr.IsValid())
+ AddAddress(addr);
+ }
+ }
+ catch (...) { }
+ }
+
+ // Get cursor
+ Dbc* pcursor = GetCursor();
+ if (!pcursor)
+ return false;
+
+ loop
+ {
+ // Read next record
+ CDataStream ssKey;
+ CDataStream ssValue;
+ int ret = ReadAtCursor(pcursor, ssKey, ssValue);
+ if (ret == DB_NOTFOUND)
+ break;
+ else if (ret != 0)
+ return false;
+
+ // Unserialize
+ string strType;
+ ssKey >> strType;
+ if (strType == "addr")
+ {
+ CAddress addr;
+ ssValue >> addr;
+ mapAddresses.insert(make_pair(addr.GetKey(), addr));
+ }
+ }
+ pcursor->close();
+
+ printf("Loaded %d addresses\n", mapAddresses.size());
+ }
+
+ return true;
+}
+
+bool LoadAddresses()
+{
+ return CAddrDB("cr+").LoadAddresses();
+}
+
+
+
+
+//
+// CWalletDB
+//
+
+static set<int64> setKeyPool;
+static CCriticalSection cs_setKeyPool;
+
+bool CWalletDB::ReadAccount(const string& strAccount, CAccount& account)
+{
+ account.SetNull();
+ return Read(make_pair(string("acc"), strAccount), account);
+}
+
+bool CWalletDB::WriteAccount(const string& strAccount, const CAccount& account)
+{
+ return Write(make_pair(string("acc"), strAccount), account);
+}
+
+bool CWalletDB::WriteAccountingEntry(const CAccountingEntry& acentry)
+{
+ return Write(make_tuple(string("acentry"), acentry.strAccount, ++nAccountingEntryNumber), acentry);
+}
+
+int64 CWalletDB::GetAccountCreditDebit(const string& strAccount)
+{
+ list<CAccountingEntry> entries;
+ ListAccountCreditDebit(strAccount, entries);
+
+ int64 nCreditDebit = 0;
+ BOOST_FOREACH (const CAccountingEntry& entry, entries)
+ nCreditDebit += entry.nCreditDebit;
+
+ return nCreditDebit;
+}
+
+void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountingEntry>& entries)
+{
+ int64 nCreditDebit = 0;
+
+ bool fAllAccounts = (strAccount == "*");
+
+ Dbc* pcursor = GetCursor();
+ if (!pcursor)
+ throw runtime_error("CWalletDB::ListAccountCreditDebit() : cannot create DB cursor");
+ unsigned int fFlags = DB_SET_RANGE;
+ loop
+ {
+ // Read next record
+ CDataStream ssKey;
+ if (fFlags == DB_SET_RANGE)
+ ssKey << make_tuple(string("acentry"), (fAllAccounts? string("") : strAccount), uint64(0));
+ CDataStream ssValue;
+ int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
+ fFlags = DB_NEXT;
+ if (ret == DB_NOTFOUND)
+ break;
+ else if (ret != 0)
+ {
+ pcursor->close();
+ throw runtime_error("CWalletDB::ListAccountCreditDebit() : error scanning DB");
+ }
+
+ // Unserialize
+ string strType;
+ ssKey >> strType;
+ if (strType != "acentry")
+ break;
+ CAccountingEntry acentry;
+ ssKey >> acentry.strAccount;
+ if (!fAllAccounts && acentry.strAccount != strAccount)
+ break;
+
+ ssValue >> acentry;
+ entries.push_back(acentry);
+ }
+
+ pcursor->close();
+}
+
+
+bool CWalletDB::LoadWallet()
+{
+ vchDefaultKey.clear();
+ int nFileVersion = 0;
+ vector<uint256> vWalletUpgrade;
+
+ // Modify defaults
+#ifndef __WXMSW__
+ // Tray icon sometimes disappears on 9.10 karmic koala 64-bit, leaving no way to access the program
+ fMinimizeToTray = false;
+ fMinimizeOnClose = false;
+#endif
+
+ //// todo: shouldn't we catch exceptions and try to recover and continue?
+ CRITICAL_BLOCK(cs_mapWallet)
+ CRITICAL_BLOCK(cs_mapKeys)
+ {
+ // Get cursor
+ Dbc* pcursor = GetCursor();
+ if (!pcursor)
+ return false;
+
+ loop
+ {
+ // Read next record
+ CDataStream ssKey;
+ CDataStream ssValue;
+ int ret = ReadAtCursor(pcursor, ssKey, ssValue);
+ if (ret == DB_NOTFOUND)
+ break;
+ else if (ret != 0)
+ return false;
+
+ // Unserialize
+ // Taking advantage of the fact that pair serialization
+ // is just the two items serialized one after the other
+ string strType;
+ ssKey >> strType;
+ if (strType == "name")
+ {
+ string strAddress;
+ ssKey >> strAddress;
+ ssValue >> mapAddressBook[strAddress];
+ }
+ else if (strType == "tx")
+ {
+ uint256 hash;
+ ssKey >> hash;
+ CWalletTx& wtx = mapWallet[hash];
+ ssValue >> wtx;
+
+ if (wtx.GetHash() != hash)
+ printf("Error in wallet.dat, hash mismatch\n");
+
+ // Undo serialize changes in 31600
+ if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703)
+ {
+ if (!ssValue.empty())
+ {
+ char fTmp;
+ char fUnused;
+ ssValue >> fTmp >> fUnused >> wtx.strFromAccount;
+ printf("LoadWallet() upgrading tx ver=%d %d '%s' %s\n", wtx.fTimeReceivedIsTxTime, fTmp, wtx.strFromAccount.c_str(), hash.ToString().c_str());
+ wtx.fTimeReceivedIsTxTime = fTmp;
+ }
+ else
+ {
+ printf("LoadWallet() repairing tx ver=%d %s\n", wtx.fTimeReceivedIsTxTime, hash.ToString().c_str());
+ wtx.fTimeReceivedIsTxTime = 0;
+ }
+ vWalletUpgrade.push_back(hash);
+ }
+
+ //// debug print
+ //printf("LoadWallet %s\n", wtx.GetHash().ToString().c_str());
+ //printf(" %12I64d %s %s %s\n",
+ // wtx.vout[0].nValue,
+ // DateTimeStrFormat("%x %H:%M:%S", wtx.GetBlockTime()).c_str(),
+ // wtx.hashBlock.ToString().substr(0,20).c_str(),
+ // wtx.mapValue["message"].c_str());
+ }
+ else if (strType == "acentry")
+ {
+ string strAccount;
+ ssKey >> strAccount;
+ uint64 nNumber;
+ ssKey >> nNumber;
+ if (nNumber > nAccountingEntryNumber)
+ nAccountingEntryNumber = nNumber;
+ }
+ else if (strType == "key" || strType == "wkey")
+ {
+ vector<unsigned char> vchPubKey;
+ ssKey >> vchPubKey;
+ CWalletKey wkey;
+ if (strType == "key")
+ ssValue >> wkey.vchPrivKey;
+ else
+ ssValue >> wkey;
+
+ mapKeys[vchPubKey] = wkey.vchPrivKey;
+ mapPubKeys[Hash160(vchPubKey)] = vchPubKey;
+ }
+ else if (strType == "defaultkey")
+ {
+ ssValue >> vchDefaultKey;
+ }
+ else if (strType == "pool")
+ {
+ int64 nIndex;
+ ssKey >> nIndex;
+ setKeyPool.insert(nIndex);
+ }
+ else if (strType == "version")
+ {
+ ssValue >> nFileVersion;
+ if (nFileVersion == 10300)
+ nFileVersion = 300;
+ }
+ else if (strType == "setting")
+ {
+ string strKey;
+ ssKey >> strKey;
+
+ // Options
+#ifndef GUI
+ if (strKey == "fGenerateBitcoins") ssValue >> fGenerateBitcoins;
+#endif
+ if (strKey == "nTransactionFee") ssValue >> nTransactionFee;
+ if (strKey == "addrIncoming") ssValue >> addrIncoming;
+ if (strKey == "fLimitProcessors") ssValue >> fLimitProcessors;
+ if (strKey == "nLimitProcessors") ssValue >> nLimitProcessors;
+ if (strKey == "fMinimizeToTray") ssValue >> fMinimizeToTray;
+ if (strKey == "fMinimizeOnClose") ssValue >> fMinimizeOnClose;
+ if (strKey == "fUseProxy") ssValue >> fUseProxy;
+ if (strKey == "addrProxy") ssValue >> addrProxy;
+ if (fHaveUPnP && strKey == "fUseUPnP") ssValue >> fUseUPnP;
+ }
+ }
+ pcursor->close();
+ }
+
+ BOOST_FOREACH(uint256 hash, vWalletUpgrade)
+ WriteTx(hash, mapWallet[hash]);
+
+ printf("nFileVersion = %d\n", nFileVersion);
+ printf("fGenerateBitcoins = %d\n", fGenerateBitcoins);
+ printf("nTransactionFee = %"PRI64d"\n", nTransactionFee);
+ printf("addrIncoming = %s\n", addrIncoming.ToString().c_str());
+ printf("fMinimizeToTray = %d\n", fMinimizeToTray);
+ printf("fMinimizeOnClose = %d\n", fMinimizeOnClose);
+ printf("fUseProxy = %d\n", fUseProxy);
+ printf("addrProxy = %s\n", addrProxy.ToString().c_str());
+ if (fHaveUPnP)
+ printf("fUseUPnP = %d\n", fUseUPnP);
+
+
+ // Upgrade
+ if (nFileVersion < VERSION)
+ {
+ // Get rid of old debug.log file in current directory
+ if (nFileVersion <= 105 && !pszSetDataDir[0])
+ unlink("debug.log");
+
+ WriteVersion(VERSION);
+ }
+
+
+ return true;
+}
+
+bool LoadWallet(bool& fFirstRunRet)
+{
+ fFirstRunRet = false;
+ if (!CWalletDB("cr+").LoadWallet())
+ return false;
+ fFirstRunRet = vchDefaultKey.empty();
+
+ if (mapKeys.count(vchDefaultKey))
+ {
+ // Set keyUser
+ keyUser.SetPubKey(vchDefaultKey);
+ keyUser.SetPrivKey(mapKeys[vchDefaultKey]);
+ }
+ else
+ {
+ // Create new keyUser and set as default key
+ RandAddSeedPerfmon();
+ keyUser.MakeNewKey();
+ if (!AddKey(keyUser))
+ return false;
+ if (!SetAddressBookName(PubKeyToAddress(keyUser.GetPubKey()), ""))
+ return false;
+ CWalletDB().WriteDefaultKey(keyUser.GetPubKey());
+ }
+
+ CreateThread(ThreadFlushWalletDB, NULL);
+ return true;
+}
+
+void ThreadFlushWalletDB(void* parg)
+{
+ static bool fOneThread;
+ if (fOneThread)
+ return;
+ fOneThread = true;
+ if (mapArgs.count("-noflushwallet"))
+ return;
+
+ unsigned int nLastSeen = nWalletDBUpdated;
+ unsigned int nLastFlushed = nWalletDBUpdated;
+ int64 nLastWalletUpdate = GetTime();
+ while (!fShutdown)
+ {
+ Sleep(500);
+
+ if (nLastSeen != nWalletDBUpdated)
+ {
+ nLastSeen = nWalletDBUpdated;
+ nLastWalletUpdate = GetTime();
+ }
+
+ if (nLastFlushed != nWalletDBUpdated && GetTime() - nLastWalletUpdate >= 2)
+ {
+ TRY_CRITICAL_BLOCK(cs_db)
+ {
+ // Don't do this if any databases are in use
+ int nRefCount = 0;
+ map<string, int>::iterator mi = mapFileUseCount.begin();
+ while (mi != mapFileUseCount.end())
+ {
+ nRefCount += (*mi).second;
+ mi++;
+ }
+
+ if (nRefCount == 0 && !fShutdown)
+ {
+ string strFile = "wallet.dat";
+ map<string, int>::iterator mi = mapFileUseCount.find(strFile);
+ if (mi != mapFileUseCount.end())
+ {
+ printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
+ printf("Flushing wallet.dat\n");
+ nLastFlushed = nWalletDBUpdated;
+ int64 nStart = GetTimeMillis();
+
+ // Flush wallet.dat so it's self contained
+ CloseDb(strFile);
+ dbenv.txn_checkpoint(0, 0, 0);
+ dbenv.lsn_reset(strFile.c_str(), 0);
+
+ mapFileUseCount.erase(mi++);
+ printf("Flushed wallet.dat %"PRI64d"ms\n", GetTimeMillis() - nStart);
+ }
+ }
+ }
+ }
+ }
+}
+
+void BackupWallet(const string& strDest)
+{
+ while (!fShutdown)
+ {
+ CRITICAL_BLOCK(cs_db)
+ {
+ const string strFile = "wallet.dat";
+ if (!mapFileUseCount.count(strFile) || mapFileUseCount[strFile] == 0)
+ {
+ // Flush log data to the dat file
+ CloseDb(strFile);
+ dbenv.txn_checkpoint(0, 0, 0);
+ dbenv.lsn_reset(strFile.c_str(), 0);
+ mapFileUseCount.erase(strFile);
+
+ // Copy wallet.dat
+ filesystem::path pathSrc(GetDataDir() + "/" + strFile);
+ filesystem::path pathDest(strDest);
+ if (filesystem::is_directory(pathDest))
+ pathDest = pathDest / strFile;
+#if BOOST_VERSION >= 104000
+ filesystem::copy_file(pathSrc, pathDest, filesystem::copy_option::overwrite_if_exists);
+#else
+ filesystem::copy_file(pathSrc, pathDest);
+#endif
+ printf("copied wallet.dat to %s\n", pathDest.string().c_str());
+
+ return;
+ }
+ }
+ Sleep(100);
+ }
+}
+
+
+void CWalletDB::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool)
+{
+ nIndex = -1;
+ keypool.vchPubKey.clear();
+ CRITICAL_BLOCK(cs_main)
+ CRITICAL_BLOCK(cs_mapWallet)
+ CRITICAL_BLOCK(cs_setKeyPool)
+ {
+ // Top up key pool
+ int64 nTargetSize = max(GetArg("-keypool", 100), (int64)0);
+ while (setKeyPool.size() < nTargetSize+1)
+ {
+ int64 nEnd = 1;
+ if (!setKeyPool.empty())
+ nEnd = *(--setKeyPool.end()) + 1;
+ if (!Write(make_pair(string("pool"), nEnd), CKeyPool(GenerateNewKey())))
+ throw runtime_error("ReserveKeyFromKeyPool() : writing generated key failed");
+ setKeyPool.insert(nEnd);
+ printf("keypool added key %"PRI64d", size=%d\n", nEnd, setKeyPool.size());
+ }
+
+ // Get the oldest key
+ assert(!setKeyPool.empty());
+ nIndex = *(setKeyPool.begin());
+ setKeyPool.erase(setKeyPool.begin());
+ if (!Read(make_pair(string("pool"), nIndex), keypool))
+ throw runtime_error("ReserveKeyFromKeyPool() : read failed");
+ if (!mapKeys.count(keypool.vchPubKey))
+ throw runtime_error("ReserveKeyFromKeyPool() : unknown key in key pool");
+ assert(!keypool.vchPubKey.empty());
+ printf("keypool reserve %"PRI64d"\n", nIndex);
+ }
+}
+
+void CWalletDB::KeepKey(int64 nIndex)
+{
+ // Remove from key pool
+ CRITICAL_BLOCK(cs_main)
+ CRITICAL_BLOCK(cs_mapWallet)
+ {
+ Erase(make_pair(string("pool"), nIndex));
+ }
+ printf("keypool keep %"PRI64d"\n", nIndex);
+}
+
+void CWalletDB::ReturnKey(int64 nIndex)
+{
+ // Return to key pool
+ CRITICAL_BLOCK(cs_setKeyPool)
+ setKeyPool.insert(nIndex);
+ printf("keypool return %"PRI64d"\n", nIndex);
+}
+
+vector<unsigned char> GetKeyFromKeyPool()
+{
+ CWalletDB walletdb;
+ int64 nIndex = 0;
+ CKeyPool keypool;
+ walletdb.ReserveKeyFromKeyPool(nIndex, keypool);
+ walletdb.KeepKey(nIndex);
+ return keypool.vchPubKey;
+}
+
+int64 GetOldestKeyPoolTime()
+{
+ CWalletDB walletdb;
+ int64 nIndex = 0;
+ CKeyPool keypool;
+ walletdb.ReserveKeyFromKeyPool(nIndex, keypool);
+ walletdb.ReturnKey(nIndex);
+ return keypool.nTime;
+}
diff --git a/core/src/init.cpp b/core/src/init.cpp
new file mode 100644
index 0000000000..3126d3489e
--- /dev/null
+++ b/core/src/init.cpp
@@ -0,0 +1,522 @@
+// 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.
+#include "headers.h"
+
+using namespace std;
+using namespace boost;
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Shutdown
+//
+
+void ExitTimeout(void* parg)
+{
+#ifdef __WXMSW__
+ Sleep(5000);
+ ExitProcess(0);
+#endif
+}
+
+void Shutdown(void* parg)
+{
+ static CCriticalSection cs_Shutdown;
+ static bool fTaken;
+ bool fFirstThread;
+ CRITICAL_BLOCK(cs_Shutdown)
+ {
+ fFirstThread = !fTaken;
+ fTaken = true;
+ }
+ static bool fExit;
+ if (fFirstThread)
+ {
+ fShutdown = true;
+ nTransactionsUpdated++;
+ DBFlush(false);
+ StopNode();
+ DBFlush(true);
+ boost::filesystem::remove(GetPidFile());
+ CreateThread(ExitTimeout, NULL);
+ Sleep(50);
+ printf("Bitcoin exiting\n\n");
+ fExit = true;
+ exit(0);
+ }
+ else
+ {
+ while (!fExit)
+ Sleep(500);
+ Sleep(100);
+ ExitThread(0);
+ }
+}
+
+void HandleSIGTERM(int)
+{
+ fRequestShutdown = true;
+}
+
+
+
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Start
+//
+#if 0
+#ifndef GUI
+int main(int argc, char* argv[])
+{
+ bool fRet = false;
+ fRet = AppInit(argc, argv);
+
+ if (fRet && fDaemon)
+ return 0;
+
+ return 1;
+}
+#endif
+#endif
+
+bool AppInit(int argc, char* argv[])
+{
+ bool fRet = false;
+ try
+ {
+ fRet = AppInit2(argc, argv);
+ }
+ catch (std::exception& e) {
+ PrintException(&e, "AppInit()");
+ } catch (...) {
+ PrintException(NULL, "AppInit()");
+ }
+ if (!fRet)
+ Shutdown(NULL);
+ return fRet;
+}
+
+bool AppInit2(int argc, char* argv[])
+{
+#ifdef _MSC_VER
+ // Turn off microsoft heap dump noise
+ _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
+ _CrtSetReportFile(_CRT_WARN, CreateFileA("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
+#endif
+#if _MSC_VER >= 1400
+ // Disable confusing "helpful" text message on abort, ctrl-c
+ _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
+#endif
+#ifndef __WXMSW__
+ umask(077);
+#endif
+#ifndef __WXMSW__
+ // Clean shutdown on SIGTERM
+ struct sigaction sa;
+ sa.sa_handler = HandleSIGTERM;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ sigaction(SIGTERM, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+ sigaction(SIGHUP, &sa, NULL);
+#endif
+
+ //
+ // Parameters
+ //
+ ParseParameters(argc, argv);
+
+ if (mapArgs.count("-datadir"))
+ {
+ filesystem::path pathDataDir = filesystem::system_complete(mapArgs["-datadir"]);
+ strlcpy(pszSetDataDir, pathDataDir.string().c_str(), sizeof(pszSetDataDir));
+ }
+
+ ReadConfigFile(mapArgs, mapMultiArgs); // Must be done after processing datadir
+
+ if (mapArgs.count("-?") || mapArgs.count("--help"))
+ {
+ string beta = VERSION_IS_BETA ? _(" beta") : "";
+ string strUsage = string() +
+ _("Bitcoin version") + " " + FormatFullVersion() + "\n\n" +
+ _("Usage:") + "\t\t\t\t\t\t\t\t\t\t\n" +
+ " bitcoin [options] \t " + "\n" +
+ " bitcoin [options] <command> [params]\t " + _("Send command to -server or bitcoind\n") +
+ " bitcoin [options] help \t\t " + _("List commands\n") +
+ " bitcoin [options] help <command> \t\t " + _("Get help for a command\n") +
+ _("Options:\n") +
+ " -conf=<file> \t\t " + _("Specify configuration file (default: bitcoin.conf)\n") +
+ " -pid=<file> \t\t " + _("Specify pid file (default: bitcoind.pid)\n") +
+ " -gen \t\t " + _("Generate coins\n") +
+ " -gen=0 \t\t " + _("Don't generate coins\n") +
+ " -min \t\t " + _("Start minimized\n") +
+ " -datadir=<dir> \t\t " + _("Specify data directory\n") +
+ " -proxy=<ip:port> \t " + _("Connect through socks4 proxy\n") +
+ " -dns \t " + _("Allow DNS lookups for addnode and connect\n") +
+ " -addnode=<ip> \t " + _("Add a node to connect to\n") +
+ " -connect=<ip> \t\t " + _("Connect only to the specified node\n") +
+ " -nolisten \t " + _("Don't accept connections from outside\n") +
+#ifdef USE_UPNP
+#if USE_UPNP
+ " -noupnp \t " + _("Don't attempt to use UPnP to map the listening port\n") +
+#else
+ " -upnp \t " + _("Attempt to use UPnP to map the listening port\n") +
+#endif
+#endif
+ " -paytxfee=<amt> \t " + _("Fee per KB to add to transactions you send\n") +
+#ifdef GUI
+ " -server \t\t " + _("Accept command line and JSON-RPC commands\n") +
+#endif
+#ifndef __WXMSW__
+ " -daemon \t\t " + _("Run in the background as a daemon and accept commands\n") +
+#endif
+ " -testnet \t\t " + _("Use the test network\n") +
+ " -rpcuser=<user> \t " + _("Username for JSON-RPC connections\n") +
+ " -rpcpassword=<pw>\t " + _("Password for JSON-RPC connections\n") +
+ " -rpcport=<port> \t\t " + _("Listen for JSON-RPC connections on <port> (default: 8332)\n") +
+ " -rpcallowip=<ip> \t\t " + _("Allow JSON-RPC connections from specified IP address\n") +
+ " -rpcconnect=<ip> \t " + _("Send commands to node running on <ip> (default: 127.0.0.1)\n") +
+ " -keypool=<n> \t " + _("Set key pool size to <n> (default: 100)\n") +
+ " -rescan \t " + _("Rescan the block chain for missing wallet transactions\n");
+
+#ifdef USE_SSL
+ strUsage += string() +
+ _("\nSSL options: (see the Bitcoin Wiki for SSL setup instructions)\n") +
+ " -rpcssl \t " + _("Use OpenSSL (https) for JSON-RPC connections\n") +
+ " -rpcsslcertificatechainfile=<file.cert>\t " + _("Server certificate file (default: server.cert)\n") +
+ " -rpcsslprivatekeyfile=<file.pem> \t " + _("Server private key (default: server.pem)\n") +
+ " -rpcsslciphers=<ciphers> \t " + _("Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH)\n");
+#endif
+
+ strUsage += string() +
+ " -? \t\t " + _("This help message\n");
+
+#if defined(__WXMSW__) && defined(GUI)
+ // Tabs make the columns line up in the message box
+ wxMessageBox(strUsage, "Bitcoin", wxOK);
+#else
+ // Remove tabs
+ strUsage.erase(std::remove(strUsage.begin(), strUsage.end(), '\t'), strUsage.end());
+ fprintf(stderr, "%s", strUsage.c_str());
+#endif
+ return false;
+ }
+
+ fDebug = GetBoolArg("-debug");
+ fAllowDNS = GetBoolArg("-dns");
+
+#ifndef __WXMSW__
+ fDaemon = GetBoolArg("-daemon");
+#else
+ fDaemon = false;
+#endif
+
+ if (fDaemon)
+ fServer = true;
+ else
+ fServer = GetBoolArg("-server");
+
+ /* force fServer when running without GUI */
+#ifndef GUI
+ fServer = true;
+#endif
+
+ fPrintToConsole = GetBoolArg("-printtoconsole");
+ fPrintToDebugger = GetBoolArg("-printtodebugger");
+
+ fTestNet = GetBoolArg("-testnet");
+ fNoListen = GetBoolArg("-nolisten");
+ fLogTimestamps = GetBoolArg("-logtimestamps");
+
+ for (int i = 1; i < argc; i++)
+ if (!IsSwitchChar(argv[i][0]))
+ fCommandLine = true;
+
+ if (fCommandLine)
+ {
+ int ret = CommandLineRPC(argc, argv);
+ exit(ret);
+ }
+
+#ifndef __WXMSW__
+ if (fDaemon)
+ {
+ // Daemonize
+ pid_t pid = fork();
+ if (pid < 0)
+ {
+ fprintf(stderr, "Error: fork() returned %d errno %d\n", pid, errno);
+ return false;
+ }
+ if (pid > 0)
+ {
+ CreatePidFile(GetPidFile(), pid);
+ return true;
+ }
+
+ pid_t sid = setsid();
+ if (sid < 0)
+ fprintf(stderr, "Error: setsid() returned %d errno %d\n", sid, errno);
+ }
+#endif
+
+ if (!fDebug && !pszSetDataDir[0])
+ ShrinkDebugFile();
+ printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
+ printf("Bitcoin version %s\n", FormatFullVersion().c_str());
+#ifdef GUI
+ printf("OS version %s\n", ((string)wxGetOsDescription()).c_str());
+ printf("System default language is %d %s\n", g_locale.GetSystemLanguage(), ((string)g_locale.GetSysName()).c_str());
+ printf("Language file %s (%s)\n", (string("locale/") + (string)g_locale.GetCanonicalName() + "/LC_MESSAGES/bitcoin.mo").c_str(), ((string)g_locale.GetLocale()).c_str());
+#endif
+ printf("Default data directory %s\n", GetDefaultDataDir().c_str());
+
+ if (GetBoolArg("-loadblockindextest"))
+ {
+ CTxDB txdb("r");
+ txdb.LoadBlockIndex();
+ PrintBlockTree();
+ return false;
+ }
+
+ //
+ // Limit to single instance per user
+ // Required to protect the database files if we're going to keep deleting log.*
+ //
+#if defined(__WXMSW__) && defined(GUI)
+ // wxSingleInstanceChecker doesn't work on Linux
+ wxString strMutexName = wxString("bitcoin_running.") + getenv("HOMEPATH");
+ for (int i = 0; i < strMutexName.size(); i++)
+ if (!isalnum(strMutexName[i]))
+ strMutexName[i] = '.';
+ wxSingleInstanceChecker* psingleinstancechecker = new wxSingleInstanceChecker(strMutexName);
+ if (psingleinstancechecker->IsAnotherRunning())
+ {
+ printf("Existing instance found\n");
+ unsigned int nStart = GetTime();
+ loop
+ {
+ // Show the previous instance and exit
+ HWND hwndPrev = FindWindowA("wxWindowClassNR", "Bitcoin");
+ if (hwndPrev)
+ {
+ if (IsIconic(hwndPrev))
+ ShowWindow(hwndPrev, SW_RESTORE);
+ SetForegroundWindow(hwndPrev);
+ return false;
+ }
+
+ if (GetTime() > nStart + 60)
+ return false;
+
+ // Resume this instance if the other exits
+ delete psingleinstancechecker;
+ Sleep(1000);
+ psingleinstancechecker = new wxSingleInstanceChecker(strMutexName);
+ if (!psingleinstancechecker->IsAnotherRunning())
+ break;
+ }
+ }
+#endif
+
+ // Make sure only a single bitcoin process is using the data directory.
+ string strLockFile = GetDataDir() + "/.lock";
+ FILE* file = fopen(strLockFile.c_str(), "a"); // empty lock file; created if it doesn't exist.
+ if (file) fclose(file);
+ static boost::interprocess::file_lock lock(strLockFile.c_str());
+ if (!lock.try_lock())
+ {
+ wxMessageBox(strprintf(_("Cannot obtain a lock on data directory %s. Bitcoin is probably already running."), GetDataDir().c_str()), "Bitcoin");
+ return false;
+ }
+
+ // Bind to the port early so we can tell if another instance is already running.
+ string strErrors;
+ if (!fNoListen)
+ {
+ if (!BindListenPort(strErrors))
+ {
+ wxMessageBox(strErrors, "Bitcoin");
+ return false;
+ }
+ }
+
+ //
+ // Load data files
+ //
+ if (fDaemon)
+ fprintf(stdout, "bitcoin server starting\n");
+ strErrors = "";
+ int64 nStart;
+
+ printf("Loading addresses...\n");
+ nStart = GetTimeMillis();
+ if (!LoadAddresses())
+ strErrors += _("Error loading addr.dat \n");
+ printf(" addresses %15"PRI64d"ms\n", GetTimeMillis() - nStart);
+
+ printf("Loading block index...\n");
+ nStart = GetTimeMillis();
+ if (!LoadBlockIndex())
+ strErrors += _("Error loading blkindex.dat \n");
+ printf(" block index %15"PRI64d"ms\n", GetTimeMillis() - nStart);
+
+ printf("Loading wallet...\n");
+ nStart = GetTimeMillis();
+ bool fFirstRun;
+ if (!LoadWallet(fFirstRun))
+ strErrors += _("Error loading wallet.dat \n");
+ printf(" wallet %15"PRI64d"ms\n", GetTimeMillis() - nStart);
+
+ CBlockIndex *pindexRescan = pindexBest;
+ if (GetBoolArg("-rescan"))
+ pindexRescan = pindexGenesisBlock;
+ else
+ {
+ CWalletDB walletdb;
+ CBlockLocator locator;
+ if (walletdb.ReadBestBlock(locator))
+ pindexRescan = locator.GetBlockIndex();
+ }
+ if (pindexBest != pindexRescan)
+ {
+ printf("Rescanning last %i blocks (from block %i)...\n", pindexBest->nHeight - pindexRescan->nHeight, pindexRescan->nHeight);
+ nStart = GetTimeMillis();
+ ScanForWalletTransactions(pindexRescan);
+ printf(" rescan %15"PRI64d"ms\n", GetTimeMillis() - nStart);
+ }
+
+ printf("Done loading\n");
+
+ //// debug print
+ printf("mapBlockIndex.size() = %d\n", mapBlockIndex.size());
+ printf("nBestHeight = %d\n", nBestHeight);
+ printf("mapKeys.size() = %d\n", mapKeys.size());
+ printf("mapPubKeys.size() = %d\n", mapPubKeys.size());
+ printf("mapWallet.size() = %d\n", mapWallet.size());
+ printf("mapAddressBook.size() = %d\n", mapAddressBook.size());
+
+ if (!strErrors.empty())
+ {
+ wxMessageBox(strErrors, "Bitcoin", wxOK | wxICON_ERROR);
+ return false;
+ }
+
+ // Add wallet transactions that aren't already in a block to mapTransactions
+ ReacceptWalletTransactions();
+
+ //
+ // Parameters
+ //
+ if (GetBoolArg("-printblockindex") || GetBoolArg("-printblocktree"))
+ {
+ PrintBlockTree();
+ return false;
+ }
+
+ if (mapArgs.count("-printblock"))
+ {
+ string strMatch = mapArgs["-printblock"];
+ int nFound = 0;
+ for (map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.begin(); mi != mapBlockIndex.end(); ++mi)
+ {
+ uint256 hash = (*mi).first;
+ if (strncmp(hash.ToString().c_str(), strMatch.c_str(), strMatch.size()) == 0)
+ {
+ CBlockIndex* pindex = (*mi).second;
+ CBlock block;
+ block.ReadFromDisk(pindex);
+ block.BuildMerkleTree();
+ block.print();
+ printf("\n");
+ nFound++;
+ }
+ }
+ if (nFound == 0)
+ printf("No blocks matching %s were found\n", strMatch.c_str());
+ return false;
+ }
+
+ fGenerateBitcoins = GetBoolArg("-gen");
+
+ if (mapArgs.count("-proxy"))
+ {
+ fUseProxy = true;
+ addrProxy = CAddress(mapArgs["-proxy"]);
+ if (!addrProxy.IsValid())
+ {
+ wxMessageBox(_("Invalid -proxy address"), "Bitcoin");
+ return false;
+ }
+ }
+
+ if (mapArgs.count("-addnode"))
+ {
+ BOOST_FOREACH(string strAddr, mapMultiArgs["-addnode"])
+ {
+ CAddress addr(strAddr, fAllowDNS);
+ addr.nTime = 0; // so it won't relay unless successfully connected
+ if (addr.IsValid())
+ AddAddress(addr);
+ }
+ }
+
+ if (mapArgs.count("-dnsseed"))
+ DNSAddressSeed();
+
+ if (mapArgs.count("-paytxfee"))
+ {
+ if (!ParseMoney(mapArgs["-paytxfee"], nTransactionFee))
+ {
+ wxMessageBox(_("Invalid amount for -paytxfee=<amount>"), "Bitcoin");
+ return false;
+ }
+ if (nTransactionFee > 0.25 * COIN)
+ wxMessageBox(_("Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction."), "Bitcoin", wxOK | wxICON_EXCLAMATION);
+ }
+
+ if (fHaveUPnP)
+ {
+#if USE_UPNP
+ if (GetBoolArg("-noupnp"))
+ fUseUPnP = false;
+#else
+ if (GetBoolArg("-upnp"))
+ fUseUPnP = true;
+#endif
+ }
+
+ //
+ // Create the main window and start the node
+ //
+#ifdef GUI
+ if (!fDaemon)
+ CreateMainWindow();
+#endif
+
+ if (!CheckDiskSpace())
+ return false;
+
+ RandAddSeedPerfmon();
+
+ if (!CreateThread(StartNode, NULL))
+ wxMessageBox("Error: CreateThread(StartNode) failed", "Bitcoin");
+
+ if (fServer)
+ CreateThread(ThreadRPCServer, NULL);
+
+#if defined(__WXMSW__) && defined(GUI)
+ if (fFirstRun)
+ SetStartOnSystemStartup(true);
+#endif
+
+#ifndef GUI
+ while (1)
+ Sleep(5000);
+#endif
+
+ return true;
+}
diff --git a/core/src/irc.cpp b/core/src/irc.cpp
new file mode 100644
index 0000000000..099d9e0735
--- /dev/null
+++ b/core/src/irc.cpp
@@ -0,0 +1,438 @@
+// 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.
+
+#include "headers.h"
+
+using namespace std;
+using namespace boost;
+
+int nGotIRCAddresses = 0;
+bool fGotExternalIP = false;
+
+void ThreadIRCSeed2(void* parg);
+
+
+
+
+#pragma pack(push, 1)
+struct ircaddr
+{
+ int ip;
+ short port;
+};
+#pragma pack(pop)
+
+string EncodeAddress(const CAddress& addr)
+{
+ struct ircaddr tmp;
+ tmp.ip = addr.ip;
+ tmp.port = addr.port;
+
+ vector<unsigned char> vch(UBEGIN(tmp), UEND(tmp));
+ return string("u") + EncodeBase58Check(vch);
+}
+
+bool DecodeAddress(string str, CAddress& addr)
+{
+ vector<unsigned char> vch;
+ if (!DecodeBase58Check(str.substr(1), vch))
+ return false;
+
+ struct ircaddr tmp;
+ if (vch.size() != sizeof(tmp))
+ return false;
+ memcpy(&tmp, &vch[0], sizeof(tmp));
+
+ addr = CAddress(tmp.ip, ntohs(tmp.port), NODE_NETWORK);
+ return true;
+}
+
+
+
+
+
+
+static bool Send(SOCKET hSocket, const char* pszSend)
+{
+ if (strstr(pszSend, "PONG") != pszSend)
+ printf("IRC SENDING: %s\n", pszSend);
+ const char* psz = pszSend;
+ const char* pszEnd = psz + strlen(psz);
+ while (psz < pszEnd)
+ {
+ int ret = send(hSocket, psz, pszEnd - psz, MSG_NOSIGNAL);
+ if (ret < 0)
+ return false;
+ psz += ret;
+ }
+ return true;
+}
+
+bool RecvLine(SOCKET hSocket, string& strLine)
+{
+ strLine = "";
+ loop
+ {
+ char c;
+ int nBytes = recv(hSocket, &c, 1, 0);
+ if (nBytes > 0)
+ {
+ if (c == '\n')
+ continue;
+ if (c == '\r')
+ return true;
+ strLine += c;
+ if (strLine.size() >= 9000)
+ return true;
+ }
+ else if (nBytes <= 0)
+ {
+ if (fShutdown)
+ return false;
+ if (nBytes < 0)
+ {
+ int nErr = WSAGetLastError();
+ if (nErr == WSAEMSGSIZE)
+ continue;
+ if (nErr == WSAEWOULDBLOCK || nErr == WSAEINTR || nErr == WSAEINPROGRESS)
+ {
+ Sleep(10);
+ continue;
+ }
+ }
+ if (!strLine.empty())
+ return true;
+ if (nBytes == 0)
+ {
+ // socket closed
+ printf("IRC socket closed\n");
+ return false;
+ }
+ else
+ {
+ // socket error
+ int nErr = WSAGetLastError();
+ printf("IRC recv failed: %d\n", nErr);
+ return false;
+ }
+ }
+ }
+}
+
+bool RecvLineIRC(SOCKET hSocket, string& strLine)
+{
+ loop
+ {
+ bool fRet = RecvLine(hSocket, strLine);
+ if (fRet)
+ {
+ if (fShutdown)
+ return false;
+ vector<string> vWords;
+ ParseString(strLine, ' ', vWords);
+ if (vWords.size() >= 1 && vWords[0] == "PING")
+ {
+ strLine[1] = 'O';
+ strLine += '\r';
+ Send(hSocket, strLine.c_str());
+ continue;
+ }
+ }
+ return fRet;
+ }
+}
+
+int RecvUntil(SOCKET hSocket, const char* psz1, const char* psz2=NULL, const char* psz3=NULL, const char* psz4=NULL)
+{
+ loop
+ {
+ string strLine;
+ strLine.reserve(10000);
+ if (!RecvLineIRC(hSocket, strLine))
+ return 0;
+ printf("IRC %s\n", strLine.c_str());
+ if (psz1 && strLine.find(psz1) != -1)
+ return 1;
+ if (psz2 && strLine.find(psz2) != -1)
+ return 2;
+ if (psz3 && strLine.find(psz3) != -1)
+ return 3;
+ if (psz4 && strLine.find(psz4) != -1)
+ return 4;
+ }
+}
+
+bool Wait(int nSeconds)
+{
+ if (fShutdown)
+ return false;
+ printf("IRC waiting %d seconds to reconnect\n", nSeconds);
+ for (int i = 0; i < nSeconds; i++)
+ {
+ if (fShutdown)
+ return false;
+ Sleep(1000);
+ }
+ return true;
+}
+
+bool RecvCodeLine(SOCKET hSocket, const char* psz1, string& strRet)
+{
+ strRet.clear();
+ loop
+ {
+ string strLine;
+ if (!RecvLineIRC(hSocket, strLine))
+ return false;
+
+ vector<string> vWords;
+ ParseString(strLine, ' ', vWords);
+ if (vWords.size() < 2)
+ continue;
+
+ if (vWords[1] == psz1)
+ {
+ printf("IRC %s\n", strLine.c_str());
+ strRet = strLine;
+ return true;
+ }
+ }
+}
+
+bool GetIPFromIRC(SOCKET hSocket, string strMyName, unsigned int& ipRet)
+{
+ Send(hSocket, strprintf("USERHOST %s\r", strMyName.c_str()).c_str());
+
+ string strLine;
+ if (!RecvCodeLine(hSocket, "302", strLine))
+ return false;
+
+ vector<string> vWords;
+ ParseString(strLine, ' ', vWords);
+ if (vWords.size() < 4)
+ return false;
+
+ string str = vWords[3];
+ if (str.rfind("@") == string::npos)
+ return false;
+ string strHost = str.substr(str.rfind("@")+1);
+
+ // Hybrid IRC used by lfnet always returns IP when you userhost yourself,
+ // but in case another IRC is ever used this should work.
+ printf("GetIPFromIRC() got userhost %s\n", strHost.c_str());
+ if (fUseProxy)
+ return false;
+ CAddress addr(strHost, 0, true);
+ if (!addr.IsValid())
+ return false;
+ ipRet = addr.ip;
+
+ return true;
+}
+
+
+
+void ThreadIRCSeed(void* parg)
+{
+ IMPLEMENT_RANDOMIZE_STACK(ThreadIRCSeed(parg));
+ try
+ {
+ ThreadIRCSeed2(parg);
+ }
+ catch (std::exception& e) {
+ PrintExceptionContinue(&e, "ThreadIRCSeed()");
+ } catch (...) {
+ PrintExceptionContinue(NULL, "ThreadIRCSeed()");
+ }
+ printf("ThreadIRCSeed exiting\n");
+}
+
+void ThreadIRCSeed2(void* parg)
+{
+ /* Dont advertise on IRC if we don't allow incoming connections */
+ if (mapArgs.count("-connect") || fNoListen)
+ return;
+
+ if (GetBoolArg("-noirc"))
+ return;
+ printf("ThreadIRCSeed started\n");
+ int nErrorWait = 10;
+ int nRetryWait = 10;
+ bool fNameInUse = false;
+ bool fTOR = (fUseProxy && addrProxy.port == htons(9050));
+
+ while (!fShutdown)
+ {
+ //CAddress addrConnect("216.155.130.130:6667"); // chat.freenode.net
+ CAddress addrConnect("92.243.23.21:6667"); // irc.lfnet.org
+ if (!fTOR)
+ {
+ //struct hostent* phostent = gethostbyname("chat.freenode.net");
+ CAddress addrIRC("irc.lfnet.org:6667", 0, true);
+ if (addrIRC.IsValid())
+ addrConnect = addrIRC;
+ }
+
+ SOCKET hSocket;
+ if (!ConnectSocket(addrConnect, hSocket))
+ {
+ printf("IRC connect failed\n");
+ nErrorWait = nErrorWait * 11 / 10;
+ if (Wait(nErrorWait += 60))
+ continue;
+ else
+ return;
+ }
+
+ if (!RecvUntil(hSocket, "Found your hostname", "using your IP address instead", "Couldn't look up your hostname", "ignoring hostname"))
+ {
+ closesocket(hSocket);
+ hSocket = INVALID_SOCKET;
+ nErrorWait = nErrorWait * 11 / 10;
+ if (Wait(nErrorWait += 60))
+ continue;
+ else
+ return;
+ }
+
+ string strMyName;
+ if (addrLocalHost.IsRoutable() && !fUseProxy && !fNameInUse)
+ strMyName = EncodeAddress(addrLocalHost);
+ else
+ strMyName = strprintf("x%u", GetRand(1000000000));
+
+ Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str());
+ Send(hSocket, strprintf("USER %s 8 * : %s\r", strMyName.c_str(), strMyName.c_str()).c_str());
+
+ int nRet = RecvUntil(hSocket, " 004 ", " 433 ");
+ if (nRet != 1)
+ {
+ closesocket(hSocket);
+ hSocket = INVALID_SOCKET;
+ if (nRet == 2)
+ {
+ printf("IRC name already in use\n");
+ fNameInUse = true;
+ Wait(10);
+ continue;
+ }
+ nErrorWait = nErrorWait * 11 / 10;
+ if (Wait(nErrorWait += 60))
+ continue;
+ else
+ return;
+ }
+ Sleep(500);
+
+ // Get our external IP from the IRC server and re-nick before joining the channel
+ CAddress addrFromIRC;
+ if (GetIPFromIRC(hSocket, strMyName, addrFromIRC.ip))
+ {
+ printf("GetIPFromIRC() returned %s\n", addrFromIRC.ToStringIP().c_str());
+ if (!fUseProxy && addrFromIRC.IsRoutable())
+ {
+ // IRC lets you to re-nick
+ fGotExternalIP = true;
+ addrLocalHost.ip = addrFromIRC.ip;
+ strMyName = EncodeAddress(addrLocalHost);
+ Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str());
+ }
+ }
+
+ Send(hSocket, fTestNet ? "JOIN #bitcoinTEST\r" : "JOIN #bitcoin\r");
+ Send(hSocket, fTestNet ? "WHO #bitcoinTEST\r" : "WHO #bitcoin\r");
+
+ int64 nStart = GetTime();
+ string strLine;
+ strLine.reserve(10000);
+ while (!fShutdown && RecvLineIRC(hSocket, strLine))
+ {
+ if (strLine.empty() || strLine.size() > 900 || strLine[0] != ':')
+ continue;
+
+ vector<string> vWords;
+ ParseString(strLine, ' ', vWords);
+ if (vWords.size() < 2)
+ continue;
+
+ char pszName[10000];
+ pszName[0] = '\0';
+
+ if (vWords[1] == "352" && vWords.size() >= 8)
+ {
+ // index 7 is limited to 16 characters
+ // could get full length name at index 10, but would be different from join messages
+ strlcpy(pszName, vWords[7].c_str(), sizeof(pszName));
+ printf("IRC got who\n");
+ }
+
+ if (vWords[1] == "JOIN" && vWords[0].size() > 1)
+ {
+ // :username!username@50000007.F000000B.90000002.IP JOIN :#channelname
+ strlcpy(pszName, vWords[0].c_str() + 1, sizeof(pszName));
+ if (strchr(pszName, '!'))
+ *strchr(pszName, '!') = '\0';
+ printf("IRC got join\n");
+ }
+
+ if (pszName[0] == 'u')
+ {
+ CAddress addr;
+ if (DecodeAddress(pszName, addr))
+ {
+ addr.nTime = GetAdjustedTime();
+ if (AddAddress(addr, 51 * 60))
+ printf("IRC got new address: %s\n", addr.ToString().c_str());
+ nGotIRCAddresses++;
+ }
+ else
+ {
+ printf("IRC decode failed\n");
+ }
+ }
+ }
+ closesocket(hSocket);
+ hSocket = INVALID_SOCKET;
+
+ // IRC usually blocks TOR, so only try once
+ if (fTOR)
+ return;
+
+ if (GetTime() - nStart > 20 * 60)
+ {
+ nErrorWait /= 3;
+ nRetryWait /= 3;
+ }
+
+ nRetryWait = nRetryWait * 11 / 10;
+ if (!Wait(nRetryWait += 60))
+ return;
+ }
+}
+
+
+
+
+
+
+
+
+
+
+#ifdef TEST
+int main(int argc, char *argv[])
+{
+ WSADATA wsadata;
+ if (WSAStartup(MAKEWORD(2,2), &wsadata) != NO_ERROR)
+ {
+ printf("Error at WSAStartup()\n");
+ return false;
+ }
+
+ ThreadIRCSeed(NULL);
+
+ WSACleanup();
+ return 0;
+}
+#endif
diff --git a/core/src/main.cpp b/core/src/main.cpp
new file mode 100644
index 0000000000..68b6b4ee1b
--- /dev/null
+++ b/core/src/main.cpp
@@ -0,0 +1,4024 @@
+// 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.
+#include "headers.h"
+#include "cryptopp/sha.h"
+
+using namespace std;
+using namespace boost;
+
+//
+// Global state
+//
+
+CCriticalSection cs_main;
+
+map<uint256, CTransaction> mapTransactions;
+CCriticalSection cs_mapTransactions;
+unsigned int nTransactionsUpdated = 0;
+map<COutPoint, CInPoint> mapNextTx;
+
+map<uint256, CBlockIndex*> mapBlockIndex;
+uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f");
+CBigNum bnProofOfWorkLimit(~uint256(0) >> 32);
+CBlockIndex* pindexGenesisBlock = NULL;
+int nBestHeight = -1;
+CBigNum bnBestChainWork = 0;
+CBigNum bnBestInvalidWork = 0;
+uint256 hashBestChain = 0;
+CBlockIndex* pindexBest = NULL;
+int64 nTimeBestReceived = 0;
+
+map<uint256, CBlock*> mapOrphanBlocks;
+multimap<uint256, CBlock*> mapOrphanBlocksByPrev;
+
+map<uint256, CDataStream*> mapOrphanTransactions;
+multimap<uint256, CDataStream*> mapOrphanTransactionsByPrev;
+
+map<uint256, CWalletTx> mapWallet;
+vector<uint256> vWalletUpdated;
+CCriticalSection cs_mapWallet;
+
+map<vector<unsigned char>, CPrivKey> mapKeys;
+map<uint160, vector<unsigned char> > mapPubKeys;
+CCriticalSection cs_mapKeys;
+CKey keyUser;
+
+map<uint256, int> mapRequestCount;
+CCriticalSection cs_mapRequestCount;
+
+map<string, string> mapAddressBook;
+CCriticalSection cs_mapAddressBook;
+
+vector<unsigned char> vchDefaultKey;
+
+double dHashesPerSec;
+int64 nHPSTimerStart;
+
+// Settings
+int fGenerateBitcoins = false;
+int64 nTransactionFee = 0;
+CAddress addrIncoming;
+int fLimitProcessors = false;
+int nLimitProcessors = 1;
+int fMinimizeToTray = true;
+int fMinimizeOnClose = true;
+#if USE_UPNP
+int fUseUPnP = true;
+#else
+int fUseUPnP = false;
+#endif
+
+
+
+
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// mapKeys
+//
+
+bool AddKey(const CKey& key)
+{
+ CRITICAL_BLOCK(cs_mapKeys)
+ {
+ mapKeys[key.GetPubKey()] = key.GetPrivKey();
+ mapPubKeys[Hash160(key.GetPubKey())] = key.GetPubKey();
+ }
+ return CWalletDB().WriteKey(key.GetPubKey(), key.GetPrivKey());
+}
+
+vector<unsigned char> GenerateNewKey()
+{
+ RandAddSeedPerfmon();
+ CKey key;
+ key.MakeNewKey();
+ if (!AddKey(key))
+ throw runtime_error("GenerateNewKey() : AddKey failed");
+ return key.GetPubKey();
+}
+
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// mapWallet
+//
+
+bool AddToWallet(const CWalletTx& wtxIn)
+{
+ uint256 hash = wtxIn.GetHash();
+ CRITICAL_BLOCK(cs_mapWallet)
+ {
+ // Inserts only if not already there, returns tx inserted or tx found
+ pair<map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(make_pair(hash, wtxIn));
+ CWalletTx& wtx = (*ret.first).second;
+ bool fInsertedNew = ret.second;
+ if (fInsertedNew)
+ wtx.nTimeReceived = GetAdjustedTime();
+
+ bool fUpdated = false;
+ if (!fInsertedNew)
+ {
+ // Merge
+ if (wtxIn.hashBlock != 0 && wtxIn.hashBlock != wtx.hashBlock)
+ {
+ wtx.hashBlock = wtxIn.hashBlock;
+ fUpdated = true;
+ }
+ if (wtxIn.nIndex != -1 && (wtxIn.vMerkleBranch != wtx.vMerkleBranch || wtxIn.nIndex != wtx.nIndex))
+ {
+ wtx.vMerkleBranch = wtxIn.vMerkleBranch;
+ wtx.nIndex = wtxIn.nIndex;
+ fUpdated = true;
+ }
+ if (wtxIn.fFromMe && wtxIn.fFromMe != wtx.fFromMe)
+ {
+ wtx.fFromMe = wtxIn.fFromMe;
+ fUpdated = true;
+ }
+ fUpdated |= wtx.UpdateSpent(wtxIn.vfSpent);
+ }
+
+ //// debug print
+ printf("AddToWallet %s %s%s\n", wtxIn.GetHash().ToString().substr(0,10).c_str(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : ""));
+
+ // Write to disk
+ if (fInsertedNew || fUpdated)
+ if (!wtx.WriteToDisk())
+ return false;
+
+ // If default receiving address gets used, replace it with a new one
+ CScript scriptDefaultKey;
+ scriptDefaultKey.SetBitcoinAddress(vchDefaultKey);
+ BOOST_FOREACH(const CTxOut& txout, wtx.vout)
+ {
+ if (txout.scriptPubKey == scriptDefaultKey)
+ {
+ CWalletDB walletdb;
+ vchDefaultKey = GetKeyFromKeyPool();
+ walletdb.WriteDefaultKey(vchDefaultKey);
+ walletdb.WriteName(PubKeyToAddress(vchDefaultKey), "");
+ }
+ }
+
+ // Notify UI
+ vWalletUpdated.push_back(hash);
+ }
+
+ // Refresh UI
+ MainFrameRepaint();
+ return true;
+}
+
+bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate = false)
+{
+ uint256 hash = tx.GetHash();
+ bool fExisted = mapWallet.count(hash);
+ if (fExisted && !fUpdate) return false;
+ if (fExisted || tx.IsMine() || tx.IsFromMe())
+ {
+ CWalletTx wtx(tx);
+ // Get merkle branch if transaction was found in a block
+ if (pblock)
+ wtx.SetMerkleBranch(pblock);
+ return AddToWallet(wtx);
+ }
+ return false;
+}
+
+bool EraseFromWallet(uint256 hash)
+{
+ CRITICAL_BLOCK(cs_mapWallet)
+ {
+ if (mapWallet.erase(hash))
+ CWalletDB().EraseTx(hash);
+ }
+ return true;
+}
+
+void WalletUpdateSpent(const COutPoint& prevout)
+{
+ // Anytime a signature is successfully verified, it's proof the outpoint is spent.
+ // Update the wallet spent flag if it doesn't know due to wallet.dat being
+ // restored from backup or the user making copies of wallet.dat.
+ CRITICAL_BLOCK(cs_mapWallet)
+ {
+ map<uint256, CWalletTx>::iterator mi = mapWallet.find(prevout.hash);
+ if (mi != mapWallet.end())
+ {
+ CWalletTx& wtx = (*mi).second;
+ if (!wtx.IsSpent(prevout.n) && wtx.vout[prevout.n].IsMine())
+ {
+ printf("WalletUpdateSpent found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
+ wtx.MarkSpent(prevout.n);
+ wtx.WriteToDisk();
+ vWalletUpdated.push_back(prevout.hash);
+ }
+ }
+ }
+}
+
+
+
+
+
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// mapOrphanTransactions
+//
+
+void AddOrphanTx(const CDataStream& vMsg)
+{
+ CTransaction tx;
+ CDataStream(vMsg) >> tx;
+ uint256 hash = tx.GetHash();
+ if (mapOrphanTransactions.count(hash))
+ return;
+ CDataStream* pvMsg = mapOrphanTransactions[hash] = new CDataStream(vMsg);
+ BOOST_FOREACH(const CTxIn& txin, tx.vin)
+ mapOrphanTransactionsByPrev.insert(make_pair(txin.prevout.hash, pvMsg));
+}
+
+void EraseOrphanTx(uint256 hash)
+{
+ if (!mapOrphanTransactions.count(hash))
+ return;
+ const CDataStream* pvMsg = mapOrphanTransactions[hash];
+ CTransaction tx;
+ CDataStream(*pvMsg) >> tx;
+ BOOST_FOREACH(const CTxIn& txin, tx.vin)
+ {
+ for (multimap<uint256, CDataStream*>::iterator mi = mapOrphanTransactionsByPrev.lower_bound(txin.prevout.hash);
+ mi != mapOrphanTransactionsByPrev.upper_bound(txin.prevout.hash);)
+ {
+ if ((*mi).second == pvMsg)
+ mapOrphanTransactionsByPrev.erase(mi++);
+ else
+ mi++;
+ }
+ }
+ delete pvMsg;
+ mapOrphanTransactions.erase(hash);
+}
+
+
+
+
+
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// CTransaction and CTxIndex
+//
+
+bool CTransaction::ReadFromDisk(CTxDB& txdb, COutPoint prevout, CTxIndex& txindexRet)
+{
+ SetNull();
+ if (!txdb.ReadTxIndex(prevout.hash, txindexRet))
+ return false;
+ if (!ReadFromDisk(txindexRet.pos))
+ return false;
+ if (prevout.n >= vout.size())
+ {
+ SetNull();
+ return false;
+ }
+ return true;
+}
+
+bool CTransaction::ReadFromDisk(CTxDB& txdb, COutPoint prevout)
+{
+ CTxIndex txindex;
+ return ReadFromDisk(txdb, prevout, txindex);
+}
+
+bool CTransaction::ReadFromDisk(COutPoint prevout)
+{
+ CTxDB txdb("r");
+ CTxIndex txindex;
+ return ReadFromDisk(txdb, prevout, txindex);
+}
+
+bool CTxIn::IsMine() const
+{
+ CRITICAL_BLOCK(cs_mapWallet)
+ {
+ map<uint256, CWalletTx>::iterator mi = mapWallet.find(prevout.hash);
+ if (mi != mapWallet.end())
+ {
+ const CWalletTx& prev = (*mi).second;
+ if (prevout.n < prev.vout.size())
+ if (prev.vout[prevout.n].IsMine())
+ return true;
+ }
+ }
+ return false;
+}
+
+int64 CTxIn::GetDebit() const
+{
+ CRITICAL_BLOCK(cs_mapWallet)
+ {
+ map<uint256, CWalletTx>::iterator mi = mapWallet.find(prevout.hash);
+ if (mi != mapWallet.end())
+ {
+ const CWalletTx& prev = (*mi).second;
+ if (prevout.n < prev.vout.size())
+ if (prev.vout[prevout.n].IsMine())
+ return prev.vout[prevout.n].nValue;
+ }
+ }
+ return 0;
+}
+
+int64 CWalletTx::GetTxTime() const
+{
+ if (!fTimeReceivedIsTxTime && hashBlock != 0)
+ {
+ // If we did not receive the transaction directly, we rely on the block's
+ // time to figure out when it happened. We use the median over a range
+ // of blocks to try to filter out inaccurate block times.
+ map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
+ if (mi != mapBlockIndex.end())
+ {
+ CBlockIndex* pindex = (*mi).second;
+ if (pindex)
+ return pindex->GetMedianTime();
+ }
+ }
+ return nTimeReceived;
+}
+
+int CWalletTx::GetRequestCount() const
+{
+ // Returns -1 if it wasn't being tracked
+ int nRequests = -1;
+ CRITICAL_BLOCK(cs_mapRequestCount)
+ {
+ if (IsCoinBase())
+ {
+ // Generated block
+ if (hashBlock != 0)
+ {
+ map<uint256, int>::iterator mi = mapRequestCount.find(hashBlock);
+ if (mi != mapRequestCount.end())
+ nRequests = (*mi).second;
+ }
+ }
+ else
+ {
+ // Did anyone request this transaction?
+ map<uint256, int>::iterator mi = mapRequestCount.find(GetHash());
+ if (mi != mapRequestCount.end())
+ {
+ nRequests = (*mi).second;
+
+ // How about the block it's in?
+ if (nRequests == 0 && hashBlock != 0)
+ {
+ map<uint256, int>::iterator mi = mapRequestCount.find(hashBlock);
+ if (mi != mapRequestCount.end())
+ nRequests = (*mi).second;
+ else
+ nRequests = 1; // If it's in someone else's block it must have got out
+ }
+ }
+ }
+ }
+ return nRequests;
+}
+
+void CWalletTx::GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, list<pair<string, int64> >& listReceived,
+ list<pair<string, int64> >& listSent, int64& nFee, string& strSentAccount) const
+{
+ nGeneratedImmature = nGeneratedMature = nFee = 0;
+ listReceived.clear();
+ listSent.clear();
+ strSentAccount = strFromAccount;
+
+ if (IsCoinBase())
+ {
+ if (GetBlocksToMaturity() > 0)
+ nGeneratedImmature = CTransaction::GetCredit();
+ else
+ nGeneratedMature = GetCredit();
+ return;
+ }
+
+ // Compute fee:
+ int64 nDebit = GetDebit();
+ if (nDebit > 0) // debit>0 means we signed/sent this transaction
+ {
+ int64 nValueOut = GetValueOut();
+ nFee = nDebit - nValueOut;
+ }
+
+ // Sent/received. Standard client will never generate a send-to-multiple-recipients,
+ // but non-standard clients might (so return a list of address/amount pairs)
+ BOOST_FOREACH(const CTxOut& txout, vout)
+ {
+ string address;
+ uint160 hash160;
+ vector<unsigned char> vchPubKey;
+ if (ExtractHash160(txout.scriptPubKey, hash160))
+ address = Hash160ToAddress(hash160);
+ else if (ExtractPubKey(txout.scriptPubKey, false, vchPubKey))
+ address = PubKeyToAddress(vchPubKey);
+ else
+ {
+ printf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n",
+ this->GetHash().ToString().c_str());
+ address = " unknown ";
+ }
+
+ // Don't report 'change' txouts
+ if (nDebit > 0 && txout.IsChange())
+ continue;
+
+ if (nDebit > 0)
+ listSent.push_back(make_pair(address, txout.nValue));
+
+ if (txout.IsMine())
+ listReceived.push_back(make_pair(address, txout.nValue));
+ }
+
+}
+
+void CWalletTx::GetAccountAmounts(const string& strAccount, int64& nGenerated, int64& nReceived,
+ int64& nSent, int64& nFee) const
+{
+ nGenerated = nReceived = nSent = nFee = 0;
+
+ int64 allGeneratedImmature, allGeneratedMature, allFee;
+ allGeneratedImmature = allGeneratedMature = allFee = 0;
+ string strSentAccount;
+ list<pair<string, int64> > listReceived;
+ list<pair<string, int64> > listSent;
+ GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
+
+ if (strAccount == "")
+ nGenerated = allGeneratedMature;
+ if (strAccount == strSentAccount)
+ {
+ BOOST_FOREACH(const PAIRTYPE(string,int64)& s, listSent)
+ nSent += s.second;
+ nFee = allFee;
+ }
+ CRITICAL_BLOCK(cs_mapAddressBook)
+ {
+ BOOST_FOREACH(const PAIRTYPE(string,int64)& r, listReceived)
+ {
+ if (mapAddressBook.count(r.first))
+ {
+ if (mapAddressBook[r.first] == strAccount)
+ {
+ nReceived += r.second;
+ }
+ }
+ else if (strAccount.empty())
+ {
+ nReceived += r.second;
+ }
+ }
+ }
+}
+
+
+
+int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
+{
+ if (fClient)
+ {
+ if (hashBlock == 0)
+ return 0;
+ }
+ else
+ {
+ CBlock blockTmp;
+ if (pblock == NULL)
+ {
+ // Load the block this tx is in
+ CTxIndex txindex;
+ if (!CTxDB("r").ReadTxIndex(GetHash(), txindex))
+ return 0;
+ if (!blockTmp.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos))
+ return 0;
+ pblock = &blockTmp;
+ }
+
+ // Update the tx's hashBlock
+ hashBlock = pblock->GetHash();
+
+ // Locate the transaction
+ for (nIndex = 0; nIndex < pblock->vtx.size(); nIndex++)
+ if (pblock->vtx[nIndex] == *(CTransaction*)this)
+ break;
+ if (nIndex == pblock->vtx.size())
+ {
+ vMerkleBranch.clear();
+ nIndex = -1;
+ printf("ERROR: SetMerkleBranch() : couldn't find tx in block\n");
+ return 0;
+ }
+
+ // Fill in merkle branch
+ vMerkleBranch = pblock->GetMerkleBranch(nIndex);
+ }
+
+ // Is the tx in a block that's in the main chain
+ map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
+ if (mi == mapBlockIndex.end())
+ return 0;
+ CBlockIndex* pindex = (*mi).second;
+ if (!pindex || !pindex->IsInMainChain())
+ return 0;
+
+ return pindexBest->nHeight - pindex->nHeight + 1;
+}
+
+
+
+void CWalletTx::AddSupportingTransactions(CTxDB& txdb)
+{
+ vtxPrev.clear();
+
+ const int COPY_DEPTH = 3;
+ if (SetMerkleBranch() < COPY_DEPTH)
+ {
+ vector<uint256> vWorkQueue;
+ BOOST_FOREACH(const CTxIn& txin, vin)
+ vWorkQueue.push_back(txin.prevout.hash);
+
+ // This critsect is OK because txdb is already open
+ CRITICAL_BLOCK(cs_mapWallet)
+ {
+ map<uint256, const CMerkleTx*> mapWalletPrev;
+ set<uint256> setAlreadyDone;
+ for (int i = 0; i < vWorkQueue.size(); i++)
+ {
+ uint256 hash = vWorkQueue[i];
+ if (setAlreadyDone.count(hash))
+ continue;
+ setAlreadyDone.insert(hash);
+
+ CMerkleTx tx;
+ if (mapWallet.count(hash))
+ {
+ tx = mapWallet[hash];
+ BOOST_FOREACH(const CMerkleTx& txWalletPrev, mapWallet[hash].vtxPrev)
+ mapWalletPrev[txWalletPrev.GetHash()] = &txWalletPrev;
+ }
+ else if (mapWalletPrev.count(hash))
+ {
+ tx = *mapWalletPrev[hash];
+ }
+ else if (!fClient && txdb.ReadDiskTx(hash, tx))
+ {
+ ;
+ }
+ else
+ {
+ printf("ERROR: AddSupportingTransactions() : unsupported transaction\n");
+ continue;
+ }
+
+ int nDepth = tx.SetMerkleBranch();
+ vtxPrev.push_back(tx);
+
+ if (nDepth < COPY_DEPTH)
+ BOOST_FOREACH(const CTxIn& txin, tx.vin)
+ vWorkQueue.push_back(txin.prevout.hash);
+ }
+ }
+ }
+
+ reverse(vtxPrev.begin(), vtxPrev.end());
+}
+
+
+
+
+
+
+
+
+
+
+
+bool CTransaction::CheckTransaction() const
+{
+ // Basic checks that don't depend on any context
+ if (vin.empty() || vout.empty())
+ return error("CTransaction::CheckTransaction() : vin or vout empty");
+
+ // Size limits
+ if (::GetSerializeSize(*this, SER_NETWORK) > MAX_BLOCK_SIZE)
+ return error("CTransaction::CheckTransaction() : size limits failed");
+
+ // Check for negative or overflow output values
+ int64 nValueOut = 0;
+ BOOST_FOREACH(const CTxOut& txout, vout)
+ {
+ if (txout.nValue < 0)
+ return error("CTransaction::CheckTransaction() : txout.nValue negative");
+ if (txout.nValue > MAX_MONEY)
+ return error("CTransaction::CheckTransaction() : txout.nValue too high");
+ nValueOut += txout.nValue;
+ if (!MoneyRange(nValueOut))
+ return error("CTransaction::CheckTransaction() : txout total out of range");
+ }
+
+ if (IsCoinBase())
+ {
+ if (vin[0].scriptSig.size() < 2 || vin[0].scriptSig.size() > 100)
+ return error("CTransaction::CheckTransaction() : coinbase script size");
+ }
+ else
+ {
+ BOOST_FOREACH(const CTxIn& txin, vin)
+ if (txin.prevout.IsNull())
+ return error("CTransaction::CheckTransaction() : prevout is null");
+ }
+
+ return true;
+}
+
+bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMissingInputs)
+{
+ if (pfMissingInputs)
+ *pfMissingInputs = false;
+
+ if (!CheckTransaction())
+ return error("AcceptToMemoryPool() : CheckTransaction failed");
+
+ // Coinbase is only valid in a block, not as a loose transaction
+ if (IsCoinBase())
+ return error("AcceptToMemoryPool() : coinbase as individual tx");
+
+ // To help v0.1.5 clients who would see it as a negative number
+ if ((int64)nLockTime > INT_MAX)
+ return error("AcceptToMemoryPool() : not accepting nLockTime beyond 2038 yet");
+
+ // Safety limits
+ unsigned int nSize = ::GetSerializeSize(*this, SER_NETWORK);
+ // Checking ECDSA signatures is a CPU bottleneck, so to avoid denial-of-service
+ // attacks disallow transactions with more than one SigOp per 34 bytes.
+ // 34 bytes because a TxOut is:
+ // 20-byte address + 8 byte bitcoin amount + 5 bytes of ops + 1 byte script length
+ if (GetSigOpCount() > nSize / 34 || nSize < 100)
+ return error("AcceptToMemoryPool() : nonstandard transaction");
+
+ // Rather not work on nonstandard transactions (unless -testnet)
+ if (!fTestNet && !IsStandard())
+ return error("AcceptToMemoryPool() : nonstandard transaction type");
+
+ // Do we already have it?
+ uint256 hash = GetHash();
+ CRITICAL_BLOCK(cs_mapTransactions)
+ if (mapTransactions.count(hash))
+ return false;
+ if (fCheckInputs)
+ if (txdb.ContainsTx(hash))
+ return false;
+
+ // Check for conflicts with in-memory transactions
+ CTransaction* ptxOld = NULL;
+ for (int i = 0; i < vin.size(); i++)
+ {
+ COutPoint outpoint = vin[i].prevout;
+ if (mapNextTx.count(outpoint))
+ {
+ // Disable replacement feature for now
+ return false;
+
+ // Allow replacing with a newer version of the same transaction
+ if (i != 0)
+ return false;
+ ptxOld = mapNextTx[outpoint].ptx;
+ if (ptxOld->IsFinal())
+ return false;
+ if (!IsNewerThan(*ptxOld))
+ return false;
+ for (int i = 0; i < vin.size(); i++)
+ {
+ COutPoint outpoint = vin[i].prevout;
+ if (!mapNextTx.count(outpoint) || mapNextTx[outpoint].ptx != ptxOld)
+ return false;
+ }
+ break;
+ }
+ }
+
+ if (fCheckInputs)
+ {
+ // Check against previous transactions
+ map<uint256, CTxIndex> mapUnused;
+ int64 nFees = 0;
+ if (!ConnectInputs(txdb, mapUnused, CDiskTxPos(1,1,1), pindexBest, nFees, false, false))
+ {
+ if (pfMissingInputs)
+ *pfMissingInputs = true;
+ return error("AcceptToMemoryPool() : ConnectInputs failed %s", hash.ToString().substr(0,10).c_str());
+ }
+
+ // Don't accept it if it can't get into a block
+ if (nFees < GetMinFee(1000))
+ return error("AcceptToMemoryPool() : not enough fees");
+
+ // Continuously rate-limit free transactions
+ // This mitigates 'penny-flooding' -- sending thousands of free transactions just to
+ // be annoying or make other's transactions take longer to confirm.
+ if (nFees < MIN_TX_FEE)
+ {
+ static CCriticalSection cs;
+ static double dFreeCount;
+ static int64 nLastTime;
+ int64 nNow = GetTime();
+
+ CRITICAL_BLOCK(cs)
+ {
+ // Use an exponentially decaying ~10-minute window:
+ dFreeCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime));
+ nLastTime = nNow;
+ // -limitfreerelay unit is thousand-bytes-per-minute
+ // At default rate it would take over a month to fill 1GB
+ if (dFreeCount > GetArg("-limitfreerelay", 15)*10*1000 && !IsFromMe())
+ return error("AcceptToMemoryPool() : free transaction rejected by rate limiter");
+ if (fDebug)
+ printf("Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize);
+ dFreeCount += nSize;
+ }
+ }
+ }
+
+ // Store transaction in memory
+ CRITICAL_BLOCK(cs_mapTransactions)
+ {
+ if (ptxOld)
+ {
+ printf("AcceptToMemoryPool() : replacing tx %s with new version\n", ptxOld->GetHash().ToString().c_str());
+ ptxOld->RemoveFromMemoryPool();
+ }
+ AddToMemoryPoolUnchecked();
+ }
+
+ ///// are we sure this is ok when loading transactions or restoring block txes
+ // If updated, erase old tx from wallet
+ if (ptxOld)
+ EraseFromWallet(ptxOld->GetHash());
+
+ printf("AcceptToMemoryPool(): accepted %s\n", hash.ToString().substr(0,10).c_str());
+ return true;
+}
+
+
+bool CTransaction::AddToMemoryPoolUnchecked()
+{
+ // Add to memory pool without checking anything. Don't call this directly,
+ // call AcceptToMemoryPool to properly check the transaction first.
+ CRITICAL_BLOCK(cs_mapTransactions)
+ {
+ uint256 hash = GetHash();
+ mapTransactions[hash] = *this;
+ for (int i = 0; i < vin.size(); i++)
+ mapNextTx[vin[i].prevout] = CInPoint(&mapTransactions[hash], i);
+ nTransactionsUpdated++;
+ }
+ return true;
+}
+
+
+bool CTransaction::RemoveFromMemoryPool()
+{
+ // Remove transaction from memory pool
+ CRITICAL_BLOCK(cs_mapTransactions)
+ {
+ BOOST_FOREACH(const CTxIn& txin, vin)
+ mapNextTx.erase(txin.prevout);
+ mapTransactions.erase(GetHash());
+ nTransactionsUpdated++;
+ }
+ return true;
+}
+
+
+
+
+
+
+int CMerkleTx::GetDepthInMainChain(int& nHeightRet) const
+{
+ if (hashBlock == 0 || nIndex == -1)
+ return 0;
+
+ // Find the block it claims to be in
+ map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
+ if (mi == mapBlockIndex.end())
+ return 0;
+ CBlockIndex* pindex = (*mi).second;
+ if (!pindex || !pindex->IsInMainChain())
+ return 0;
+
+ // Make sure the merkle branch connects to this block
+ if (!fMerkleVerified)
+ {
+ if (CBlock::CheckMerkleBranch(GetHash(), vMerkleBranch, nIndex) != pindex->hashMerkleRoot)
+ return 0;
+ fMerkleVerified = true;
+ }
+
+ nHeightRet = pindex->nHeight;
+ return pindexBest->nHeight - pindex->nHeight + 1;
+}
+
+
+int CMerkleTx::GetBlocksToMaturity() const
+{
+ if (!IsCoinBase())
+ return 0;
+ return max(0, (COINBASE_MATURITY+20) - GetDepthInMainChain());
+}
+
+
+bool CMerkleTx::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs)
+{
+ if (fClient)
+ {
+ if (!IsInMainChain() && !ClientConnectInputs())
+ return false;
+ return CTransaction::AcceptToMemoryPool(txdb, false);
+ }
+ else
+ {
+ return CTransaction::AcceptToMemoryPool(txdb, fCheckInputs);
+ }
+}
+
+
+
+bool CWalletTx::AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs)
+{
+ CRITICAL_BLOCK(cs_mapTransactions)
+ {
+ // Add previous supporting transactions first
+ BOOST_FOREACH(CMerkleTx& tx, vtxPrev)
+ {
+ if (!tx.IsCoinBase())
+ {
+ uint256 hash = tx.GetHash();
+ if (!mapTransactions.count(hash) && !txdb.ContainsTx(hash))
+ tx.AcceptToMemoryPool(txdb, fCheckInputs);
+ }
+ }
+ return AcceptToMemoryPool(txdb, fCheckInputs);
+ }
+ return false;
+}
+
+int ScanForWalletTransactions(CBlockIndex* pindexStart)
+{
+ int ret = 0;
+
+ CBlockIndex* pindex = pindexStart;
+ CRITICAL_BLOCK(cs_mapWallet)
+ {
+ while (pindex)
+ {
+ CBlock block;
+ block.ReadFromDisk(pindex, true);
+ BOOST_FOREACH(CTransaction& tx, block.vtx)
+ {
+ if (AddToWalletIfInvolvingMe(tx, &block))
+ ret++;
+ }
+ pindex = pindex->pnext;
+ }
+ }
+ return ret;
+}
+
+void ReacceptWalletTransactions()
+{
+ CTxDB txdb("r");
+ bool fRepeat = true;
+ while (fRepeat) CRITICAL_BLOCK(cs_mapWallet)
+ {
+ fRepeat = false;
+ vector<CDiskTxPos> vMissingTx;
+ BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
+ {
+ CWalletTx& wtx = item.second;
+ if (wtx.IsCoinBase() && wtx.IsSpent(0))
+ continue;
+
+ CTxIndex txindex;
+ bool fUpdated = false;
+ if (txdb.ReadTxIndex(wtx.GetHash(), txindex))
+ {
+ // Update fSpent if a tx got spent somewhere else by a copy of wallet.dat
+ if (txindex.vSpent.size() != wtx.vout.size())
+ {
+ printf("ERROR: ReacceptWalletTransactions() : txindex.vSpent.size() %d != wtx.vout.size() %d\n", txindex.vSpent.size(), wtx.vout.size());
+ continue;
+ }
+ for (int i = 0; i < txindex.vSpent.size(); i++)
+ {
+ if (wtx.IsSpent(i))
+ continue;
+ if (!txindex.vSpent[i].IsNull() && wtx.vout[i].IsMine())
+ {
+ wtx.MarkSpent(i);
+ fUpdated = true;
+ vMissingTx.push_back(txindex.vSpent[i]);
+ }
+ }
+ if (fUpdated)
+ {
+ printf("ReacceptWalletTransactions found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
+ wtx.MarkDirty();
+ wtx.WriteToDisk();
+ }
+ }
+ else
+ {
+ // Reaccept any txes of ours that aren't already in a block
+ if (!wtx.IsCoinBase())
+ wtx.AcceptWalletTransaction(txdb, false);
+ }
+ }
+ if (!vMissingTx.empty())
+ {
+ // TODO: optimize this to scan just part of the block chain?
+ if (ScanForWalletTransactions(pindexGenesisBlock))
+ fRepeat = true; // Found missing transactions: re-do Reaccept.
+ }
+ }
+}
+
+
+void CWalletTx::RelayWalletTransaction(CTxDB& txdb)
+{
+ BOOST_FOREACH(const CMerkleTx& tx, vtxPrev)
+ {
+ if (!tx.IsCoinBase())
+ {
+ uint256 hash = tx.GetHash();
+ if (!txdb.ContainsTx(hash))
+ RelayMessage(CInv(MSG_TX, hash), (CTransaction)tx);
+ }
+ }
+ if (!IsCoinBase())
+ {
+ uint256 hash = GetHash();
+ if (!txdb.ContainsTx(hash))
+ {
+ printf("Relaying wtx %s\n", hash.ToString().substr(0,10).c_str());
+ RelayMessage(CInv(MSG_TX, hash), (CTransaction)*this);
+ }
+ }
+}
+
+void ResendWalletTransactions()
+{
+ // Do this infrequently and randomly to avoid giving away
+ // that these are our transactions.
+ static int64 nNextTime;
+ if (GetTime() < nNextTime)
+ return;
+ bool fFirst = (nNextTime == 0);
+ nNextTime = GetTime() + GetRand(30 * 60);
+ if (fFirst)
+ return;
+
+ // Only do it if there's been a new block since last time
+ static int64 nLastTime;
+ if (nTimeBestReceived < nLastTime)
+ return;
+ nLastTime = GetTime();
+
+ // Rebroadcast any of our txes that aren't in a block yet
+ printf("ResendWalletTransactions()\n");
+ CTxDB txdb("r");
+ CRITICAL_BLOCK(cs_mapWallet)
+ {
+ // Sort them in chronological order
+ multimap<unsigned int, CWalletTx*> mapSorted;
+ BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
+ {
+ CWalletTx& wtx = item.second;
+ // Don't rebroadcast until it's had plenty of time that
+ // it should have gotten in already by now.
+ if (nTimeBestReceived - (int64)wtx.nTimeReceived > 5 * 60)
+ mapSorted.insert(make_pair(wtx.nTimeReceived, &wtx));
+ }
+ BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted)
+ {
+ CWalletTx& wtx = *item.second;
+ wtx.RelayWalletTransaction(txdb);
+ }
+ }
+}
+
+int CTxIndex::GetDepthInMainChain() const
+{
+ // Read block header
+ CBlock block;
+ if (!block.ReadFromDisk(pos.nFile, pos.nBlockPos, false))
+ return 0;
+ // Find the block in the index
+ map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(block.GetHash());
+ if (mi == mapBlockIndex.end())
+ return 0;
+ CBlockIndex* pindex = (*mi).second;
+ if (!pindex || !pindex->IsInMainChain())
+ return 0;
+ return 1 + nBestHeight - pindex->nHeight;
+}
+
+
+
+
+
+
+
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// CBlock and CBlockIndex
+//
+
+bool CBlock::ReadFromDisk(const CBlockIndex* pindex, bool fReadTransactions)
+{
+ if (!fReadTransactions)
+ {
+ *this = pindex->GetBlockHeader();
+ return true;
+ }
+ if (!ReadFromDisk(pindex->nFile, pindex->nBlockPos, fReadTransactions))
+ return false;
+ if (GetHash() != pindex->GetBlockHash())
+ return error("CBlock::ReadFromDisk() : GetHash() doesn't match index");
+ return true;
+}
+
+uint256 GetOrphanRoot(const CBlock* pblock)
+{
+ // Work back to the first block in the orphan chain
+ while (mapOrphanBlocks.count(pblock->hashPrevBlock))
+ pblock = mapOrphanBlocks[pblock->hashPrevBlock];
+ return pblock->GetHash();
+}
+
+int64 GetBlockValue(int nHeight, int64 nFees)
+{
+ int64 nSubsidy = 50 * COIN;
+
+ // Subsidy is cut in half every 4 years
+ nSubsidy >>= (nHeight / 210000);
+
+ return nSubsidy + nFees;
+}
+
+unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast)
+{
+ const int64 nTargetTimespan = 14 * 24 * 60 * 60; // two weeks
+ const int64 nTargetSpacing = 10 * 60;
+ const int64 nInterval = nTargetTimespan / nTargetSpacing;
+
+ // Genesis block
+ if (pindexLast == NULL)
+ return bnProofOfWorkLimit.GetCompact();
+
+ // Only change once per interval
+ if ((pindexLast->nHeight+1) % nInterval != 0)
+ return pindexLast->nBits;
+
+ // Go back by what we want to be 14 days worth of blocks
+ const CBlockIndex* pindexFirst = pindexLast;
+ for (int i = 0; pindexFirst && i < nInterval-1; i++)
+ pindexFirst = pindexFirst->pprev;
+ assert(pindexFirst);
+
+ // Limit adjustment step
+ int64 nActualTimespan = pindexLast->GetBlockTime() - pindexFirst->GetBlockTime();
+ printf(" nActualTimespan = %"PRI64d" before bounds\n", nActualTimespan);
+ if (nActualTimespan < nTargetTimespan/4)
+ nActualTimespan = nTargetTimespan/4;
+ if (nActualTimespan > nTargetTimespan*4)
+ nActualTimespan = nTargetTimespan*4;
+
+ // Retarget
+ CBigNum bnNew;
+ bnNew.SetCompact(pindexLast->nBits);
+ bnNew *= nActualTimespan;
+ bnNew /= nTargetTimespan;
+
+ if (bnNew > bnProofOfWorkLimit)
+ bnNew = bnProofOfWorkLimit;
+
+ /// debug print
+ printf("GetNextWorkRequired RETARGET\n");
+ printf("nTargetTimespan = %"PRI64d" nActualTimespan = %"PRI64d"\n", nTargetTimespan, nActualTimespan);
+ printf("Before: %08x %s\n", pindexLast->nBits, CBigNum().SetCompact(pindexLast->nBits).getuint256().ToString().c_str());
+ printf("After: %08x %s\n", bnNew.GetCompact(), bnNew.getuint256().ToString().c_str());
+
+ return bnNew.GetCompact();
+}
+
+bool CheckProofOfWork(uint256 hash, unsigned int nBits)
+{
+ CBigNum bnTarget;
+ bnTarget.SetCompact(nBits);
+
+ // Check range
+ if (bnTarget <= 0 || bnTarget > bnProofOfWorkLimit)
+ return error("CheckProofOfWork() : nBits below minimum work");
+
+ // Check proof of work matches claimed amount
+ if (hash > bnTarget.getuint256())
+ return error("CheckProofOfWork() : hash doesn't match nBits");
+
+ return true;
+}
+
+bool IsInitialBlockDownload()
+{
+ if (pindexBest == NULL || (!fTestNet && nBestHeight < 118000))
+ return true;
+ static int64 nLastUpdate;
+ static CBlockIndex* pindexLastBest;
+ if (pindexBest != pindexLastBest)
+ {
+ pindexLastBest = pindexBest;
+ nLastUpdate = GetTime();
+ }
+ return (GetTime() - nLastUpdate < 10 &&
+ pindexBest->GetBlockTime() < GetTime() - 24 * 60 * 60);
+}
+
+void InvalidChainFound(CBlockIndex* pindexNew)
+{
+ if (pindexNew->bnChainWork > bnBestInvalidWork)
+ {
+ bnBestInvalidWork = pindexNew->bnChainWork;
+ CTxDB().WriteBestInvalidWork(bnBestInvalidWork);
+ MainFrameRepaint();
+ }
+ printf("InvalidChainFound: invalid block=%s height=%d work=%s\n", pindexNew->GetBlockHash().ToString().substr(0,20).c_str(), pindexNew->nHeight, pindexNew->bnChainWork.ToString().c_str());
+ printf("InvalidChainFound: current best=%s height=%d work=%s\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, bnBestChainWork.ToString().c_str());
+ if (pindexBest && bnBestInvalidWork > bnBestChainWork + pindexBest->GetBlockWork() * 6)
+ printf("InvalidChainFound: WARNING: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade.\n");
+}
+
+
+
+
+
+
+
+
+
+
+
+bool CTransaction::DisconnectInputs(CTxDB& txdb)
+{
+ // Relinquish previous transactions' spent pointers
+ if (!IsCoinBase())
+ {
+ BOOST_FOREACH(const CTxIn& txin, vin)
+ {
+ COutPoint prevout = txin.prevout;
+
+ // Get prev txindex from disk
+ CTxIndex txindex;
+ if (!txdb.ReadTxIndex(prevout.hash, txindex))
+ return error("DisconnectInputs() : ReadTxIndex failed");
+
+ if (prevout.n >= txindex.vSpent.size())
+ return error("DisconnectInputs() : prevout.n out of range");
+
+ // Mark outpoint as not spent
+ txindex.vSpent[prevout.n].SetNull();
+
+ // Write back
+ if (!txdb.UpdateTxIndex(prevout.hash, txindex))
+ return error("DisconnectInputs() : UpdateTxIndex failed");
+ }
+ }
+
+ // Remove transaction from index
+ if (!txdb.EraseTxIndex(*this))
+ return error("DisconnectInputs() : EraseTxPos failed");
+
+ return true;
+}
+
+
+bool CTransaction::ConnectInputs(CTxDB& txdb, map<uint256, CTxIndex>& mapTestPool, CDiskTxPos posThisTx,
+ CBlockIndex* pindexBlock, int64& nFees, bool fBlock, bool fMiner, int64 nMinFee)
+{
+ // Take over previous transactions' spent pointers
+ if (!IsCoinBase())
+ {
+ int64 nValueIn = 0;
+ for (int i = 0; i < vin.size(); i++)
+ {
+ COutPoint prevout = vin[i].prevout;
+
+ // Read txindex
+ CTxIndex txindex;
+ bool fFound = true;
+ if (fMiner && mapTestPool.count(prevout.hash))
+ {
+ // Get txindex from current proposed changes
+ txindex = mapTestPool[prevout.hash];
+ }
+ else
+ {
+ // Read txindex from txdb
+ fFound = txdb.ReadTxIndex(prevout.hash, txindex);
+ }
+ if (!fFound && (fBlock || fMiner))
+ return fMiner ? false : error("ConnectInputs() : %s prev tx %s index entry not found", GetHash().ToString().substr(0,10).c_str(), prevout.hash.ToString().substr(0,10).c_str());
+
+ // Read txPrev
+ CTransaction txPrev;
+ if (!fFound || txindex.pos == CDiskTxPos(1,1,1))
+ {
+ // Get prev tx from single transactions in memory
+ CRITICAL_BLOCK(cs_mapTransactions)
+ {
+ if (!mapTransactions.count(prevout.hash))
+ return error("ConnectInputs() : %s mapTransactions prev not found %s", GetHash().ToString().substr(0,10).c_str(), prevout.hash.ToString().substr(0,10).c_str());
+ txPrev = mapTransactions[prevout.hash];
+ }
+ if (!fFound)
+ txindex.vSpent.resize(txPrev.vout.size());
+ }
+ else
+ {
+ // Get prev tx from disk
+ if (!txPrev.ReadFromDisk(txindex.pos))
+ return error("ConnectInputs() : %s ReadFromDisk prev tx %s failed", GetHash().ToString().substr(0,10).c_str(), prevout.hash.ToString().substr(0,10).c_str());
+ }
+
+ if (prevout.n >= txPrev.vout.size() || prevout.n >= txindex.vSpent.size())
+ return error("ConnectInputs() : %s prevout.n out of range %d %d %d prev tx %s\n%s", GetHash().ToString().substr(0,10).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,10).c_str(), txPrev.ToString().c_str());
+
+ // If prev is coinbase, check that it's matured
+ if (txPrev.IsCoinBase())
+ for (CBlockIndex* pindex = pindexBlock; pindex && pindexBlock->nHeight - pindex->nHeight < COINBASE_MATURITY; pindex = pindex->pprev)
+ if (pindex->nBlockPos == txindex.pos.nBlockPos && pindex->nFile == txindex.pos.nFile)
+ return error("ConnectInputs() : tried to spend coinbase at depth %d", pindexBlock->nHeight - pindex->nHeight);
+
+ // Verify signature
+ if (!VerifySignature(txPrev, *this, i))
+ return error("ConnectInputs() : %s VerifySignature failed", GetHash().ToString().substr(0,10).c_str());
+
+ // Check for conflicts
+ if (!txindex.vSpent[prevout.n].IsNull())
+ return fMiner ? false : error("ConnectInputs() : %s prev tx already used at %s", GetHash().ToString().substr(0,10).c_str(), txindex.vSpent[prevout.n].ToString().c_str());
+
+ // Check for negative or overflow input values
+ nValueIn += txPrev.vout[prevout.n].nValue;
+ if (!MoneyRange(txPrev.vout[prevout.n].nValue) || !MoneyRange(nValueIn))
+ return error("ConnectInputs() : txin values out of range");
+
+ // Mark outpoints as spent
+ txindex.vSpent[prevout.n] = posThisTx;
+
+ // Write back
+ if (fBlock)
+ {
+ if (!txdb.UpdateTxIndex(prevout.hash, txindex))
+ return error("ConnectInputs() : UpdateTxIndex failed");
+ }
+ else if (fMiner)
+ {
+ mapTestPool[prevout.hash] = txindex;
+ }
+ }
+
+ if (nValueIn < GetValueOut())
+ return error("ConnectInputs() : %s value in < value out", GetHash().ToString().substr(0,10).c_str());
+
+ // Tally transaction fees
+ int64 nTxFee = nValueIn - GetValueOut();
+ if (nTxFee < 0)
+ return error("ConnectInputs() : %s nTxFee < 0", GetHash().ToString().substr(0,10).c_str());
+ if (nTxFee < nMinFee)
+ return false;
+ nFees += nTxFee;
+ if (!MoneyRange(nFees))
+ return error("ConnectInputs() : nFees out of range");
+ }
+
+ if (fBlock)
+ {
+ // Add transaction to disk index
+ if (!txdb.AddTxIndex(*this, posThisTx, pindexBlock->nHeight))
+ return error("ConnectInputs() : AddTxPos failed");
+ }
+ else if (fMiner)
+ {
+ // Add transaction to test pool
+ mapTestPool[GetHash()] = CTxIndex(CDiskTxPos(1,1,1), vout.size());
+ }
+
+ return true;
+}
+
+
+bool CTransaction::ClientConnectInputs()
+{
+ if (IsCoinBase())
+ return false;
+
+ // Take over previous transactions' spent pointers
+ CRITICAL_BLOCK(cs_mapTransactions)
+ {
+ int64 nValueIn = 0;
+ for (int i = 0; i < vin.size(); i++)
+ {
+ // Get prev tx from single transactions in memory
+ COutPoint prevout = vin[i].prevout;
+ if (!mapTransactions.count(prevout.hash))
+ return false;
+ CTransaction& txPrev = mapTransactions[prevout.hash];
+
+ if (prevout.n >= txPrev.vout.size())
+ return false;
+
+ // Verify signature
+ if (!VerifySignature(txPrev, *this, i))
+ return error("ConnectInputs() : VerifySignature failed");
+
+ ///// this is redundant with the mapNextTx stuff, not sure which I want to get rid of
+ ///// this has to go away now that posNext is gone
+ // // Check for conflicts
+ // if (!txPrev.vout[prevout.n].posNext.IsNull())
+ // return error("ConnectInputs() : prev tx already used");
+ //
+ // // Flag outpoints as used
+ // txPrev.vout[prevout.n].posNext = posThisTx;
+
+ nValueIn += txPrev.vout[prevout.n].nValue;
+
+ if (!MoneyRange(txPrev.vout[prevout.n].nValue) || !MoneyRange(nValueIn))
+ return error("ClientConnectInputs() : txin values out of range");
+ }
+ if (GetValueOut() > nValueIn)
+ return false;
+ }
+
+ return true;
+}
+
+
+
+
+bool CBlock::DisconnectBlock(CTxDB& txdb, CBlockIndex* pindex)
+{
+ // Disconnect in reverse order
+ for (int i = vtx.size()-1; i >= 0; i--)
+ if (!vtx[i].DisconnectInputs(txdb))
+ return false;
+
+ // Update block index on disk without changing it in memory.
+ // The memory index structure will be changed after the db commits.
+ if (pindex->pprev)
+ {
+ CDiskBlockIndex blockindexPrev(pindex->pprev);
+ blockindexPrev.hashNext = 0;
+ if (!txdb.WriteBlockIndex(blockindexPrev))
+ return error("DisconnectBlock() : WriteBlockIndex failed");
+ }
+
+ return true;
+}
+
+bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex)
+{
+ // Check it again in case a previous version let a bad block in
+ if (!CheckBlock())
+ return false;
+
+ //// issue here: it doesn't know the version
+ unsigned int nTxPos = pindex->nBlockPos + ::GetSerializeSize(CBlock(), SER_DISK) - 1 + GetSizeOfCompactSize(vtx.size());
+
+ map<uint256, CTxIndex> mapUnused;
+ int64 nFees = 0;
+ BOOST_FOREACH(CTransaction& tx, vtx)
+ {
+ CDiskTxPos posThisTx(pindex->nFile, pindex->nBlockPos, nTxPos);
+ nTxPos += ::GetSerializeSize(tx, SER_DISK);
+
+ if (!tx.ConnectInputs(txdb, mapUnused, posThisTx, pindex, nFees, true, false))
+ return false;
+ }
+
+ if (vtx[0].GetValueOut() > GetBlockValue(pindex->nHeight, nFees))
+ return false;
+
+ // Update block index on disk without changing it in memory.
+ // The memory index structure will be changed after the db commits.
+ if (pindex->pprev)
+ {
+ CDiskBlockIndex blockindexPrev(pindex->pprev);
+ blockindexPrev.hashNext = pindex->GetBlockHash();
+ if (!txdb.WriteBlockIndex(blockindexPrev))
+ return error("ConnectBlock() : WriteBlockIndex failed");
+ }
+
+ // Watch for transactions paying to me
+ BOOST_FOREACH(CTransaction& tx, vtx)
+ AddToWalletIfInvolvingMe(tx, this, true);
+
+ return true;
+}
+
+bool Reorganize(CTxDB& txdb, CBlockIndex* pindexNew)
+{
+ printf("REORGANIZE\n");
+
+ // Find the fork
+ CBlockIndex* pfork = pindexBest;
+ CBlockIndex* plonger = pindexNew;
+ while (pfork != plonger)
+ {
+ while (plonger->nHeight > pfork->nHeight)
+ if (!(plonger = plonger->pprev))
+ return error("Reorganize() : plonger->pprev is null");
+ if (pfork == plonger)
+ break;
+ if (!(pfork = pfork->pprev))
+ return error("Reorganize() : pfork->pprev is null");
+ }
+
+ // List of what to disconnect
+ vector<CBlockIndex*> vDisconnect;
+ for (CBlockIndex* pindex = pindexBest; pindex != pfork; pindex = pindex->pprev)
+ vDisconnect.push_back(pindex);
+
+ // List of what to connect
+ vector<CBlockIndex*> vConnect;
+ for (CBlockIndex* pindex = pindexNew; pindex != pfork; pindex = pindex->pprev)
+ vConnect.push_back(pindex);
+ reverse(vConnect.begin(), vConnect.end());
+
+ // Disconnect shorter branch
+ vector<CTransaction> vResurrect;
+ BOOST_FOREACH(CBlockIndex* pindex, vDisconnect)
+ {
+ CBlock block;
+ if (!block.ReadFromDisk(pindex))
+ return error("Reorganize() : ReadFromDisk for disconnect failed");
+ if (!block.DisconnectBlock(txdb, pindex))
+ return error("Reorganize() : DisconnectBlock failed");
+
+ // Queue memory transactions to resurrect
+ BOOST_FOREACH(const CTransaction& tx, block.vtx)
+ if (!tx.IsCoinBase())
+ vResurrect.push_back(tx);
+ }
+
+ // Connect longer branch
+ vector<CTransaction> vDelete;
+ for (int i = 0; i < vConnect.size(); i++)
+ {
+ CBlockIndex* pindex = vConnect[i];
+ CBlock block;
+ if (!block.ReadFromDisk(pindex))
+ return error("Reorganize() : ReadFromDisk for connect failed");
+ if (!block.ConnectBlock(txdb, pindex))
+ {
+ // Invalid block
+ txdb.TxnAbort();
+ return error("Reorganize() : ConnectBlock failed");
+ }
+
+ // Queue memory transactions to delete
+ BOOST_FOREACH(const CTransaction& tx, block.vtx)
+ vDelete.push_back(tx);
+ }
+ if (!txdb.WriteHashBestChain(pindexNew->GetBlockHash()))
+ return error("Reorganize() : WriteHashBestChain failed");
+
+ // Make sure it's successfully written to disk before changing memory structure
+ if (!txdb.TxnCommit())
+ return error("Reorganize() : TxnCommit failed");
+
+ // Disconnect shorter branch
+ BOOST_FOREACH(CBlockIndex* pindex, vDisconnect)
+ if (pindex->pprev)
+ pindex->pprev->pnext = NULL;
+
+ // Connect longer branch
+ BOOST_FOREACH(CBlockIndex* pindex, vConnect)
+ if (pindex->pprev)
+ pindex->pprev->pnext = pindex;
+
+ // Resurrect memory transactions that were in the disconnected branch
+ BOOST_FOREACH(CTransaction& tx, vResurrect)
+ tx.AcceptToMemoryPool(txdb, false);
+
+ // Delete redundant memory transactions that are in the connected branch
+ BOOST_FOREACH(CTransaction& tx, vDelete)
+ tx.RemoveFromMemoryPool();
+
+ return true;
+}
+
+
+bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew)
+{
+ uint256 hash = GetHash();
+
+ txdb.TxnBegin();
+ if (pindexGenesisBlock == NULL && hash == hashGenesisBlock)
+ {
+ txdb.WriteHashBestChain(hash);
+ if (!txdb.TxnCommit())
+ return error("SetBestChain() : TxnCommit failed");
+ pindexGenesisBlock = pindexNew;
+ }
+ else if (hashPrevBlock == hashBestChain)
+ {
+ // Adding to current best branch
+ if (!ConnectBlock(txdb, pindexNew) || !txdb.WriteHashBestChain(hash))
+ {
+ txdb.TxnAbort();
+ InvalidChainFound(pindexNew);
+ return error("SetBestChain() : ConnectBlock failed");
+ }
+ if (!txdb.TxnCommit())
+ return error("SetBestChain() : TxnCommit failed");
+
+ // Add to current best branch
+ pindexNew->pprev->pnext = pindexNew;
+
+ // Delete redundant memory transactions
+ BOOST_FOREACH(CTransaction& tx, vtx)
+ tx.RemoveFromMemoryPool();
+ }
+ else
+ {
+ // New best branch
+ if (!Reorganize(txdb, pindexNew))
+ {
+ txdb.TxnAbort();
+ InvalidChainFound(pindexNew);
+ return error("SetBestChain() : Reorganize failed");
+ }
+ }
+
+ // Update best block in wallet (so we can detect restored wallets)
+ if (!IsInitialBlockDownload())
+ {
+ CWalletDB walletdb;
+ const CBlockLocator locator(pindexNew);
+ if (!walletdb.WriteBestBlock(locator))
+ return error("SetBestChain() : WriteWalletBest failed");
+ }
+
+ // New best block
+ hashBestChain = hash;
+ pindexBest = pindexNew;
+ nBestHeight = pindexBest->nHeight;
+ bnBestChainWork = pindexNew->bnChainWork;
+ nTimeBestReceived = GetTime();
+ nTransactionsUpdated++;
+ printf("SetBestChain: new best=%s height=%d work=%s\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, bnBestChainWork.ToString().c_str());
+
+ return true;
+}
+
+
+bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos)
+{
+ // Check for duplicate
+ uint256 hash = GetHash();
+ if (mapBlockIndex.count(hash))
+ return error("AddToBlockIndex() : %s already exists", hash.ToString().substr(0,20).c_str());
+
+ // Construct new block index object
+ CBlockIndex* pindexNew = new CBlockIndex(nFile, nBlockPos, *this);
+ if (!pindexNew)
+ return error("AddToBlockIndex() : new CBlockIndex failed");
+ map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first;
+ pindexNew->phashBlock = &((*mi).first);
+ map<uint256, CBlockIndex*>::iterator miPrev = mapBlockIndex.find(hashPrevBlock);
+ if (miPrev != mapBlockIndex.end())
+ {
+ pindexNew->pprev = (*miPrev).second;
+ pindexNew->nHeight = pindexNew->pprev->nHeight + 1;
+ }
+ pindexNew->bnChainWork = (pindexNew->pprev ? pindexNew->pprev->bnChainWork : 0) + pindexNew->GetBlockWork();
+
+ CTxDB txdb;
+ txdb.TxnBegin();
+ txdb.WriteBlockIndex(CDiskBlockIndex(pindexNew));
+ if (!txdb.TxnCommit())
+ return false;
+
+ // New best
+ if (pindexNew->bnChainWork > bnBestChainWork)
+ if (!SetBestChain(txdb, pindexNew))
+ return false;
+
+ txdb.Close();
+
+ if (pindexNew == pindexBest)
+ {
+ // Notify UI to display prev block's coinbase if it was ours
+ static uint256 hashPrevBestCoinBase;
+ CRITICAL_BLOCK(cs_mapWallet)
+ vWalletUpdated.push_back(hashPrevBestCoinBase);
+ hashPrevBestCoinBase = vtx[0].GetHash();
+ }
+
+ MainFrameRepaint();
+ return true;
+}
+
+
+
+
+bool CBlock::CheckBlock() const
+{
+ // These are checks that are independent of context
+ // that can be verified before saving an orphan block.
+
+ // Size limits
+ if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(*this, SER_NETWORK) > MAX_BLOCK_SIZE)
+ return error("CheckBlock() : size limits failed");
+
+ // Check proof of work matches claimed amount
+ if (!CheckProofOfWork(GetHash(), nBits))
+ return error("CheckBlock() : proof of work failed");
+
+ // Check timestamp
+ if (GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60)
+ return error("CheckBlock() : block timestamp too far in the future");
+
+ // First transaction must be coinbase, the rest must not be
+ if (vtx.empty() || !vtx[0].IsCoinBase())
+ return error("CheckBlock() : first tx is not coinbase");
+ for (int i = 1; i < vtx.size(); i++)
+ if (vtx[i].IsCoinBase())
+ return error("CheckBlock() : more than one coinbase");
+
+ // Check transactions
+ BOOST_FOREACH(const CTransaction& tx, vtx)
+ if (!tx.CheckTransaction())
+ return error("CheckBlock() : CheckTransaction failed");
+
+ // Check that it's not full of nonstandard transactions
+ if (GetSigOpCount() > MAX_BLOCK_SIGOPS)
+ return error("CheckBlock() : too many nonstandard transactions");
+
+ // Check merkleroot
+ if (hashMerkleRoot != BuildMerkleTree())
+ return error("CheckBlock() : hashMerkleRoot mismatch");
+
+ return true;
+}
+
+bool CBlock::AcceptBlock()
+{
+ // Check for duplicate
+ uint256 hash = GetHash();
+ if (mapBlockIndex.count(hash))
+ return error("AcceptBlock() : block already in mapBlockIndex");
+
+ // Get prev block index
+ map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashPrevBlock);
+ if (mi == mapBlockIndex.end())
+ return error("AcceptBlock() : prev block not found");
+ CBlockIndex* pindexPrev = (*mi).second;
+ int nHeight = pindexPrev->nHeight+1;
+
+ // Check proof of work
+ if (nBits != GetNextWorkRequired(pindexPrev))
+ return error("AcceptBlock() : incorrect proof of work");
+
+ // Check timestamp against prev
+ if (GetBlockTime() <= pindexPrev->GetMedianTimePast())
+ return error("AcceptBlock() : block's timestamp is too early");
+
+ // Check that all transactions are finalized
+ BOOST_FOREACH(const CTransaction& tx, vtx)
+ if (!tx.IsFinal(nHeight, GetBlockTime()))
+ return error("AcceptBlock() : contains a non-final transaction");
+
+ // Check that the block chain matches the known block chain up to a checkpoint
+ if (!fTestNet)
+ if ((nHeight == 11111 && hash != uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d")) ||
+ (nHeight == 33333 && hash != uint256("0x000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6")) ||
+ (nHeight == 68555 && hash != uint256("0x00000000001e1b4903550a0b96e9a9405c8a95f387162e4944e8d9fbe501cd6a")) ||
+ (nHeight == 70567 && hash != uint256("0x00000000006a49b14bcf27462068f1264c961f11fa2e0eddd2be0791e1d4124a")) ||
+ (nHeight == 74000 && hash != uint256("0x0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20")) ||
+ (nHeight == 105000 && hash != uint256("0x00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97")) ||
+ (nHeight == 118000 && hash != uint256("0x000000000000774a7f8a7a12dc906ddb9e17e75d684f15e00f8767f9e8f36553")))
+ return error("AcceptBlock() : rejected by checkpoint lockin at %d", nHeight);
+
+ // Write block to history file
+ if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK)))
+ return error("AcceptBlock() : out of disk space");
+ unsigned int nFile = -1;
+ unsigned int nBlockPos = 0;
+ if (!WriteToDisk(nFile, nBlockPos))
+ return error("AcceptBlock() : WriteToDisk failed");
+ if (!AddToBlockIndex(nFile, nBlockPos))
+ return error("AcceptBlock() : AddToBlockIndex failed");
+
+ // Relay inventory, but don't relay old inventory during initial block download
+ if (hashBestChain == hash)
+ CRITICAL_BLOCK(cs_vNodes)
+ BOOST_FOREACH(CNode* pnode, vNodes)
+ if (nBestHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : 118000))
+ pnode->PushInventory(CInv(MSG_BLOCK, hash));
+
+ return true;
+}
+
+bool ProcessBlock(CNode* pfrom, CBlock* pblock)
+{
+ // Check for duplicate
+ uint256 hash = pblock->GetHash();
+ if (mapBlockIndex.count(hash))
+ return error("ProcessBlock() : already have block %d %s", mapBlockIndex[hash]->nHeight, hash.ToString().substr(0,20).c_str());
+ if (mapOrphanBlocks.count(hash))
+ return error("ProcessBlock() : already have block (orphan) %s", hash.ToString().substr(0,20).c_str());
+
+ // Preliminary checks
+ if (!pblock->CheckBlock())
+ return error("ProcessBlock() : CheckBlock FAILED");
+
+ // If don't already have its previous block, shunt it off to holding area until we get it
+ if (!mapBlockIndex.count(pblock->hashPrevBlock))
+ {
+ printf("ProcessBlock: ORPHAN BLOCK, prev=%s\n", pblock->hashPrevBlock.ToString().substr(0,20).c_str());
+ CBlock* pblock2 = new CBlock(*pblock);
+ mapOrphanBlocks.insert(make_pair(hash, pblock2));
+ mapOrphanBlocksByPrev.insert(make_pair(pblock2->hashPrevBlock, pblock2));
+
+ // Ask this guy to fill in what we're missing
+ if (pfrom)
+ pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(pblock2));
+ return true;
+ }
+
+ // Store to disk
+ if (!pblock->AcceptBlock())
+ return error("ProcessBlock() : AcceptBlock FAILED");
+
+ // Recursively process any orphan blocks that depended on this one
+ vector<uint256> vWorkQueue;
+ vWorkQueue.push_back(hash);
+ for (int i = 0; i < vWorkQueue.size(); i++)
+ {
+ uint256 hashPrev = vWorkQueue[i];
+ for (multimap<uint256, CBlock*>::iterator mi = mapOrphanBlocksByPrev.lower_bound(hashPrev);
+ mi != mapOrphanBlocksByPrev.upper_bound(hashPrev);
+ ++mi)
+ {
+ CBlock* pblockOrphan = (*mi).second;
+ if (pblockOrphan->AcceptBlock())
+ vWorkQueue.push_back(pblockOrphan->GetHash());
+ mapOrphanBlocks.erase(pblockOrphan->GetHash());
+ delete pblockOrphan;
+ }
+ mapOrphanBlocksByPrev.erase(hashPrev);
+ }
+
+ printf("ProcessBlock: ACCEPTED\n");
+ return true;
+}
+
+
+
+
+
+
+
+
+template<typename Stream>
+bool ScanMessageStart(Stream& s)
+{
+ // Scan ahead to the next pchMessageStart, which should normally be immediately
+ // at the file pointer. Leaves file pointer at end of pchMessageStart.
+ s.clear(0);
+ short prevmask = s.exceptions(0);
+ const char* p = BEGIN(pchMessageStart);
+ try
+ {
+ loop
+ {
+ char c;
+ s.read(&c, 1);
+ if (s.fail())
+ {
+ s.clear(0);
+ s.exceptions(prevmask);
+ return false;
+ }
+ if (*p != c)
+ p = BEGIN(pchMessageStart);
+ if (*p == c)
+ {
+ if (++p == END(pchMessageStart))
+ {
+ s.clear(0);
+ s.exceptions(prevmask);
+ return true;
+ }
+ }
+ }
+ }
+ catch (...)
+ {
+ s.clear(0);
+ s.exceptions(prevmask);
+ return false;
+ }
+}
+
+bool CheckDiskSpace(uint64 nAdditionalBytes)
+{
+ uint64 nFreeBytesAvailable = filesystem::space(GetDataDir()).available;
+
+ // Check for 15MB because database could create another 10MB log file at any time
+ if (nFreeBytesAvailable < (uint64)15000000 + nAdditionalBytes)
+ {
+ fShutdown = true;
+ string strMessage = _("Warning: Disk space is low ");
+ strMiscWarning = strMessage;
+ printf("*** %s\n", strMessage.c_str());
+ ThreadSafeMessageBox(strMessage, "Bitcoin", wxOK | wxICON_EXCLAMATION);
+ CreateThread(Shutdown, NULL);
+ return false;
+ }
+ return true;
+}
+
+FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszMode)
+{
+ if (nFile == -1)
+ return NULL;
+ FILE* file = fopen(strprintf("%s/blk%04d.dat", GetDataDir().c_str(), nFile).c_str(), pszMode);
+ if (!file)
+ return NULL;
+ if (nBlockPos != 0 && !strchr(pszMode, 'a') && !strchr(pszMode, 'w'))
+ {
+ if (fseek(file, nBlockPos, SEEK_SET) != 0)
+ {
+ fclose(file);
+ return NULL;
+ }
+ }
+ return file;
+}
+
+static unsigned int nCurrentBlockFile = 1;
+
+FILE* AppendBlockFile(unsigned int& nFileRet)
+{
+ nFileRet = 0;
+ loop
+ {
+ FILE* file = OpenBlockFile(nCurrentBlockFile, 0, "ab");
+ if (!file)
+ return NULL;
+ if (fseek(file, 0, SEEK_END) != 0)
+ return NULL;
+ // FAT32 filesize max 4GB, fseek and ftell max 2GB, so we must stay under 2GB
+ if (ftell(file) < 0x7F000000 - MAX_SIZE)
+ {
+ nFileRet = nCurrentBlockFile;
+ return file;
+ }
+ fclose(file);
+ nCurrentBlockFile++;
+ }
+}
+
+bool LoadBlockIndex(bool fAllowNew)
+{
+ if (fTestNet)
+ {
+ hashGenesisBlock = uint256("0x00000007199508e34a9ff81e6ec0c477a4cccff2a4767a8eee39c11db367b008");
+ bnProofOfWorkLimit = CBigNum(~uint256(0) >> 28);
+ pchMessageStart[0] = 0xfa;
+ pchMessageStart[1] = 0xbf;
+ pchMessageStart[2] = 0xb5;
+ pchMessageStart[3] = 0xda;
+ }
+
+ //
+ // Load block index
+ //
+ CTxDB txdb("cr");
+ if (!txdb.LoadBlockIndex())
+ return false;
+ txdb.Close();
+
+ //
+ // Init with genesis block
+ //
+ if (mapBlockIndex.empty())
+ {
+ if (!fAllowNew)
+ return false;
+
+ // Genesis Block:
+ // CBlock(hash=000000000019d6, ver=1, hashPrevBlock=00000000000000, hashMerkleRoot=4a5e1e, nTime=1231006505, nBits=1d00ffff, nNonce=2083236893, vtx=1)
+ // CTransaction(hash=4a5e1e, ver=1, vin.size=1, vout.size=1, nLockTime=0)
+ // CTxIn(COutPoint(000000, -1), coinbase 04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73)
+ // CTxOut(nValue=50.00000000, scriptPubKey=0x5F1DF16B2B704C8A578D0B)
+ // vMerkleTree: 4a5e1e
+
+ // Genesis block
+ const char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks";
+ CTransaction txNew;
+ txNew.vin.resize(1);
+ txNew.vout.resize(1);
+ txNew.vin[0].scriptSig = CScript() << 486604799 << CBigNum(4) << vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
+ txNew.vout[0].nValue = 50 * COIN;
+ txNew.vout[0].scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG;
+ CBlock block;
+ block.vtx.push_back(txNew);
+ block.hashPrevBlock = 0;
+ block.hashMerkleRoot = block.BuildMerkleTree();
+ block.nVersion = 1;
+ block.nTime = 1231006505;
+ block.nBits = 0x1d00ffff;
+ block.nNonce = 2083236893;
+
+ if (fTestNet)
+ {
+ block.nTime = 1296688602;
+ block.nBits = 0x1d07fff8;
+ block.nNonce = 384568319;
+ }
+
+ //// debug print
+ printf("%s\n", block.GetHash().ToString().c_str());
+ printf("%s\n", hashGenesisBlock.ToString().c_str());
+ printf("%s\n", block.hashMerkleRoot.ToString().c_str());
+ assert(block.hashMerkleRoot == uint256("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
+ block.print();
+ assert(block.GetHash() == hashGenesisBlock);
+
+ // Start new block file
+ unsigned int nFile;
+ unsigned int nBlockPos;
+ if (!block.WriteToDisk(nFile, nBlockPos))
+ return error("LoadBlockIndex() : writing genesis block to disk failed");
+ if (!block.AddToBlockIndex(nFile, nBlockPos))
+ return error("LoadBlockIndex() : genesis block not accepted");
+ }
+
+ return true;
+}
+
+
+
+void PrintBlockTree()
+{
+ // precompute tree structure
+ map<CBlockIndex*, vector<CBlockIndex*> > mapNext;
+ for (map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.begin(); mi != mapBlockIndex.end(); ++mi)
+ {
+ CBlockIndex* pindex = (*mi).second;
+ mapNext[pindex->pprev].push_back(pindex);
+ // test
+ //while (rand() % 3 == 0)
+ // mapNext[pindex->pprev].push_back(pindex);
+ }
+
+ vector<pair<int, CBlockIndex*> > vStack;
+ vStack.push_back(make_pair(0, pindexGenesisBlock));
+
+ int nPrevCol = 0;
+ while (!vStack.empty())
+ {
+ int nCol = vStack.back().first;
+ CBlockIndex* pindex = vStack.back().second;
+ vStack.pop_back();
+
+ // print split or gap
+ if (nCol > nPrevCol)
+ {
+ for (int i = 0; i < nCol-1; i++)
+ printf("| ");
+ printf("|\\\n");
+ }
+ else if (nCol < nPrevCol)
+ {
+ for (int i = 0; i < nCol; i++)
+ printf("| ");
+ printf("|\n");
+ }
+ nPrevCol = nCol;
+
+ // print columns
+ for (int i = 0; i < nCol; i++)
+ printf("| ");
+
+ // print item
+ CBlock block;
+ block.ReadFromDisk(pindex);
+ printf("%d (%u,%u) %s %s tx %d",
+ pindex->nHeight,
+ pindex->nFile,
+ pindex->nBlockPos,
+ block.GetHash().ToString().substr(0,20).c_str(),
+ DateTimeStrFormat("%x %H:%M:%S", block.GetBlockTime()).c_str(),
+ block.vtx.size());
+
+ CRITICAL_BLOCK(cs_mapWallet)
+ {
+ if (mapWallet.count(block.vtx[0].GetHash()))
+ {
+ CWalletTx& wtx = mapWallet[block.vtx[0].GetHash()];
+ printf(" mine: %d %d %d", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit());
+ }
+ }
+ printf("\n");
+
+
+ // put the main timechain first
+ vector<CBlockIndex*>& vNext = mapNext[pindex];
+ for (int i = 0; i < vNext.size(); i++)
+ {
+ if (vNext[i]->pnext)
+ {
+ swap(vNext[0], vNext[i]);
+ break;
+ }
+ }
+
+ // iterate children
+ for (int i = 0; i < vNext.size(); i++)
+ vStack.push_back(make_pair(nCol+i, vNext[i]));
+ }
+}
+
+
+
+
+
+
+
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// CAlert
+//
+
+map<uint256, CAlert> mapAlerts;
+CCriticalSection cs_mapAlerts;
+
+string GetWarnings(string strFor)
+{
+ int nPriority = 0;
+ string strStatusBar;
+ string strRPC;
+ if (GetBoolArg("-testsafemode"))
+ strRPC = "test";
+
+ // Misc warnings like out of disk space and clock is wrong
+ if (strMiscWarning != "")
+ {
+ nPriority = 1000;
+ strStatusBar = strMiscWarning;
+ }
+
+ // Longer invalid proof-of-work chain
+ if (pindexBest && bnBestInvalidWork > bnBestChainWork + pindexBest->GetBlockWork() * 6)
+ {
+ nPriority = 2000;
+ strStatusBar = strRPC = "WARNING: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade.";
+ }
+
+ // Alerts
+ CRITICAL_BLOCK(cs_mapAlerts)
+ {
+ BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
+ {
+ const CAlert& alert = item.second;
+ if (alert.AppliesToMe() && alert.nPriority > nPriority)
+ {
+ nPriority = alert.nPriority;
+ strStatusBar = alert.strStatusBar;
+ }
+ }
+ }
+
+ if (strFor == "statusbar")
+ return strStatusBar;
+ else if (strFor == "rpc")
+ return strRPC;
+ assert(("GetWarnings() : invalid parameter", false));
+ return "error";
+}
+
+bool CAlert::ProcessAlert()
+{
+ if (!CheckSignature())
+ return false;
+ if (!IsInEffect())
+ return false;
+
+ CRITICAL_BLOCK(cs_mapAlerts)
+ {
+ // Cancel previous alerts
+ for (map<uint256, CAlert>::iterator mi = mapAlerts.begin(); mi != mapAlerts.end();)
+ {
+ const CAlert& alert = (*mi).second;
+ if (Cancels(alert))
+ {
+ printf("cancelling alert %d\n", alert.nID);
+ mapAlerts.erase(mi++);
+ }
+ else if (!alert.IsInEffect())
+ {
+ printf("expiring alert %d\n", alert.nID);
+ mapAlerts.erase(mi++);
+ }
+ else
+ mi++;
+ }
+
+ // Check if this alert has been cancelled
+ BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
+ {
+ const CAlert& alert = item.second;
+ if (alert.Cancels(*this))
+ {
+ printf("alert already cancelled by %d\n", alert.nID);
+ return false;
+ }
+ }
+
+ // Add to mapAlerts
+ mapAlerts.insert(make_pair(GetHash(), *this));
+ }
+
+ printf("accepted alert %d, AppliesToMe()=%d\n", nID, AppliesToMe());
+ MainFrameRepaint();
+ return true;
+}
+
+
+
+
+
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Messages
+//
+
+
+bool AlreadyHave(CTxDB& txdb, const CInv& inv)
+{
+ switch (inv.type)
+ {
+ case MSG_TX: return mapTransactions.count(inv.hash) || mapOrphanTransactions.count(inv.hash) || txdb.ContainsTx(inv.hash);
+ case MSG_BLOCK: return mapBlockIndex.count(inv.hash) || mapOrphanBlocks.count(inv.hash);
+ }
+ // Don't know what it is, just say we already got one
+ return true;
+}
+
+
+
+
+// The message start string is designed to be unlikely to occur in normal data.
+// The characters are rarely used upper ascii, not valid as UTF-8, and produce
+// a large 4-byte int at any alignment.
+char pchMessageStart[4] = { 0xf9, 0xbe, 0xb4, 0xd9 };
+
+
+bool ProcessMessages(CNode* pfrom)
+{
+ CDataStream& vRecv = pfrom->vRecv;
+ if (vRecv.empty())
+ return true;
+ //if (fDebug)
+ // printf("ProcessMessages(%u bytes)\n", vRecv.size());
+
+ //
+ // Message format
+ // (4) message start
+ // (12) command
+ // (4) size
+ // (4) checksum
+ // (x) data
+ //
+
+ loop
+ {
+ // Scan for message start
+ CDataStream::iterator pstart = search(vRecv.begin(), vRecv.end(), BEGIN(pchMessageStart), END(pchMessageStart));
+ int nHeaderSize = vRecv.GetSerializeSize(CMessageHeader());
+ if (vRecv.end() - pstart < nHeaderSize)
+ {
+ if (vRecv.size() > nHeaderSize)
+ {
+ printf("\n\nPROCESSMESSAGE MESSAGESTART NOT FOUND\n\n");
+ vRecv.erase(vRecv.begin(), vRecv.end() - nHeaderSize);
+ }
+ break;
+ }
+ if (pstart - vRecv.begin() > 0)
+ printf("\n\nPROCESSMESSAGE SKIPPED %d BYTES\n\n", pstart - vRecv.begin());
+ vRecv.erase(vRecv.begin(), pstart);
+
+ // Read header
+ vector<char> vHeaderSave(vRecv.begin(), vRecv.begin() + nHeaderSize);
+ CMessageHeader hdr;
+ vRecv >> hdr;
+ if (!hdr.IsValid())
+ {
+ printf("\n\nPROCESSMESSAGE: ERRORS IN HEADER %s\n\n\n", hdr.GetCommand().c_str());
+ continue;
+ }
+ string strCommand = hdr.GetCommand();
+
+ // Message size
+ unsigned int nMessageSize = hdr.nMessageSize;
+ if (nMessageSize > MAX_SIZE)
+ {
+ printf("ProcessMessage(%s, %u bytes) : nMessageSize > MAX_SIZE\n", strCommand.c_str(), nMessageSize);
+ continue;
+ }
+ if (nMessageSize > vRecv.size())
+ {
+ // Rewind and wait for rest of message
+ vRecv.insert(vRecv.begin(), vHeaderSave.begin(), vHeaderSave.end());
+ break;
+ }
+
+ // Checksum
+ if (vRecv.GetVersion() >= 209)
+ {
+ uint256 hash = Hash(vRecv.begin(), vRecv.begin() + nMessageSize);
+ unsigned int nChecksum = 0;
+ memcpy(&nChecksum, &hash, sizeof(nChecksum));
+ if (nChecksum != hdr.nChecksum)
+ {
+ printf("ProcessMessage(%s, %u bytes) : CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n",
+ strCommand.c_str(), nMessageSize, nChecksum, hdr.nChecksum);
+ continue;
+ }
+ }
+
+ // Copy message to its own buffer
+ CDataStream vMsg(vRecv.begin(), vRecv.begin() + nMessageSize, vRecv.nType, vRecv.nVersion);
+ vRecv.ignore(nMessageSize);
+
+ // Process message
+ bool fRet = false;
+ try
+ {
+ CRITICAL_BLOCK(cs_main)
+ fRet = ProcessMessage(pfrom, strCommand, vMsg);
+ if (fShutdown)
+ return true;
+ }
+ catch (std::ios_base::failure& e)
+ {
+ if (strstr(e.what(), "end of data"))
+ {
+ // Allow exceptions from underlength message on vRecv
+ printf("ProcessMessage(%s, %u bytes) : Exception '%s' caught, normally caused by a message being shorter than its stated length\n", strCommand.c_str(), nMessageSize, e.what());
+ }
+ else if (strstr(e.what(), "size too large"))
+ {
+ // Allow exceptions from overlong size
+ printf("ProcessMessage(%s, %u bytes) : Exception '%s' caught\n", strCommand.c_str(), nMessageSize, e.what());
+ }
+ else
+ {
+ PrintExceptionContinue(&e, "ProcessMessage()");
+ }
+ }
+ catch (std::exception& e) {
+ PrintExceptionContinue(&e, "ProcessMessage()");
+ } catch (...) {
+ PrintExceptionContinue(NULL, "ProcessMessage()");
+ }
+
+ if (!fRet)
+ printf("ProcessMessage(%s, %u bytes) FAILED\n", strCommand.c_str(), nMessageSize);
+ }
+
+ vRecv.Compact();
+ return true;
+}
+
+
+
+
+bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
+{
+ static map<unsigned int, vector<unsigned char> > mapReuseKey;
+ RandAddSeedPerfmon();
+ if (fDebug)
+ printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
+ printf("received: %s (%d bytes)\n", strCommand.c_str(), vRecv.size());
+ if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0)
+ {
+ printf("dropmessagestest DROPPING RECV MESSAGE\n");
+ return true;
+ }
+
+
+
+
+
+ if (strCommand == "version")
+ {
+ // Each connection can only send one version message
+ if (pfrom->nVersion != 0)
+ return false;
+
+ int64 nTime;
+ CAddress addrMe;
+ CAddress addrFrom;
+ uint64 nNonce = 1;
+ vRecv >> pfrom->nVersion >> pfrom->nServices >> nTime >> addrMe;
+ if (pfrom->nVersion == 10300)
+ pfrom->nVersion = 300;
+ if (pfrom->nVersion >= 106 && !vRecv.empty())
+ vRecv >> addrFrom >> nNonce;
+ if (pfrom->nVersion >= 106 && !vRecv.empty())
+ vRecv >> pfrom->strSubVer;
+ if (pfrom->nVersion >= 209 && !vRecv.empty())
+ vRecv >> pfrom->nStartingHeight;
+
+ if (pfrom->nVersion == 0)
+ return false;
+
+ // Disconnect if we connected to ourself
+ if (nNonce == nLocalHostNonce && nNonce > 1)
+ {
+ printf("connected to self at %s, disconnecting\n", pfrom->addr.ToString().c_str());
+ pfrom->fDisconnect = true;
+ return true;
+ }
+
+ // Be shy and don't send version until we hear
+ if (pfrom->fInbound)
+ pfrom->PushVersion();
+
+ pfrom->fClient = !(pfrom->nServices & NODE_NETWORK);
+
+ AddTimeData(pfrom->addr.ip, nTime);
+
+ // Change version
+ if (pfrom->nVersion >= 209)
+ pfrom->PushMessage("verack");
+ pfrom->vSend.SetVersion(min(pfrom->nVersion, VERSION));
+ if (pfrom->nVersion < 209)
+ pfrom->vRecv.SetVersion(min(pfrom->nVersion, VERSION));
+
+ if (!pfrom->fInbound)
+ {
+ // Advertise our address
+ if (addrLocalHost.IsRoutable() && !fUseProxy)
+ {
+ CAddress addr(addrLocalHost);
+ addr.nTime = GetAdjustedTime();
+ pfrom->PushAddress(addr);
+ }
+
+ // Get recent addresses
+ if (pfrom->nVersion >= 31402 || mapAddresses.size() < 1000)
+ {
+ pfrom->PushMessage("getaddr");
+ pfrom->fGetAddr = true;
+ }
+ }
+
+ // Ask the first connected node for block updates
+ static int nAskedForBlocks;
+ if (!pfrom->fClient && (nAskedForBlocks < 1 || vNodes.size() <= 1))
+ {
+ nAskedForBlocks++;
+ pfrom->PushGetBlocks(pindexBest, uint256(0));
+ }
+
+ // Relay alerts
+ CRITICAL_BLOCK(cs_mapAlerts)
+ BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
+ item.second.RelayTo(pfrom);
+
+ pfrom->fSuccessfullyConnected = true;
+
+ printf("version message: version %d, blocks=%d\n", pfrom->nVersion, pfrom->nStartingHeight);
+ }
+
+
+ else if (pfrom->nVersion == 0)
+ {
+ // Must have a version message before anything else
+ return false;
+ }
+
+
+ else if (strCommand == "verack")
+ {
+ pfrom->vRecv.SetVersion(min(pfrom->nVersion, VERSION));
+ }
+
+
+ else if (strCommand == "addr")
+ {
+ vector<CAddress> vAddr;
+ vRecv >> vAddr;
+
+ // Don't want addr from older versions unless seeding
+ if (pfrom->nVersion < 209)
+ return true;
+ if (pfrom->nVersion < 31402 && mapAddresses.size() > 1000)
+ return true;
+ if (vAddr.size() > 1000)
+ return error("message addr size() = %d", vAddr.size());
+
+ // Store the new addresses
+ int64 nNow = GetAdjustedTime();
+ int64 nSince = nNow - 10 * 60;
+ BOOST_FOREACH(CAddress& addr, vAddr)
+ {
+ if (fShutdown)
+ return true;
+ // ignore IPv6 for now, since it isn't implemented anyway
+ if (!addr.IsIPv4())
+ continue;
+ if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60)
+ addr.nTime = nNow - 5 * 24 * 60 * 60;
+ AddAddress(addr, 2 * 60 * 60);
+ pfrom->AddAddressKnown(addr);
+ if (addr.nTime > nSince && !pfrom->fGetAddr && vAddr.size() <= 10 && addr.IsRoutable())
+ {
+ // Relay to a limited number of other nodes
+ CRITICAL_BLOCK(cs_vNodes)
+ {
+ // Use deterministic randomness to send to the same nodes for 24 hours
+ // at a time so the setAddrKnowns of the chosen nodes prevent repeats
+ static uint256 hashSalt;
+ if (hashSalt == 0)
+ RAND_bytes((unsigned char*)&hashSalt, sizeof(hashSalt));
+ uint256 hashRand = hashSalt ^ (((int64)addr.ip)<<32) ^ ((GetTime()+addr.ip)/(24*60*60));
+ hashRand = Hash(BEGIN(hashRand), END(hashRand));
+ multimap<uint256, CNode*> mapMix;
+ BOOST_FOREACH(CNode* pnode, vNodes)
+ {
+ if (pnode->nVersion < 31402)
+ continue;
+ unsigned int nPointer;
+ memcpy(&nPointer, &pnode, sizeof(nPointer));
+ uint256 hashKey = hashRand ^ nPointer;
+ hashKey = Hash(BEGIN(hashKey), END(hashKey));
+ mapMix.insert(make_pair(hashKey, pnode));
+ }
+ int nRelayNodes = 2;
+ for (multimap<uint256, CNode*>::iterator mi = mapMix.begin(); mi != mapMix.end() && nRelayNodes-- > 0; ++mi)
+ ((*mi).second)->PushAddress(addr);
+ }
+ }
+ }
+ if (vAddr.size() < 1000)
+ pfrom->fGetAddr = false;
+ }
+
+
+ else if (strCommand == "inv")
+ {
+ vector<CInv> vInv;
+ vRecv >> vInv;
+ if (vInv.size() > 50000)
+ return error("message inv size() = %d", vInv.size());
+
+ CTxDB txdb("r");
+ BOOST_FOREACH(const CInv& inv, vInv)
+ {
+ if (fShutdown)
+ return true;
+ pfrom->AddInventoryKnown(inv);
+
+ bool fAlreadyHave = AlreadyHave(txdb, inv);
+ printf(" got inventory: %s %s\n", inv.ToString().c_str(), fAlreadyHave ? "have" : "new");
+
+ if (!fAlreadyHave)
+ pfrom->AskFor(inv);
+ else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash))
+ pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(mapOrphanBlocks[inv.hash]));
+
+ // Track requests for our stuff
+ CRITICAL_BLOCK(cs_mapRequestCount)
+ {
+ map<uint256, int>::iterator mi = mapRequestCount.find(inv.hash);
+ if (mi != mapRequestCount.end())
+ (*mi).second++;
+ }
+ }
+ }
+
+
+ else if (strCommand == "getdata")
+ {
+ vector<CInv> vInv;
+ vRecv >> vInv;
+ if (vInv.size() > 50000)
+ return error("message getdata size() = %d", vInv.size());
+
+ BOOST_FOREACH(const CInv& inv, vInv)
+ {
+ if (fShutdown)
+ return true;
+ printf("received getdata for: %s\n", inv.ToString().c_str());
+
+ if (inv.type == MSG_BLOCK)
+ {
+ // Send block from disk
+ map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(inv.hash);
+ if (mi != mapBlockIndex.end())
+ {
+ CBlock block;
+ block.ReadFromDisk((*mi).second);
+ pfrom->PushMessage("block", block);
+
+ // Trigger them to send a getblocks request for the next batch of inventory
+ if (inv.hash == pfrom->hashContinue)
+ {
+ // Bypass PushInventory, this must send even if redundant,
+ // and we want it right after the last block so they don't
+ // wait for other stuff first.
+ vector<CInv> vInv;
+ vInv.push_back(CInv(MSG_BLOCK, hashBestChain));
+ pfrom->PushMessage("inv", vInv);
+ pfrom->hashContinue = 0;
+ }
+ }
+ }
+ else if (inv.IsKnownType())
+ {
+ // Send stream from relay memory
+ CRITICAL_BLOCK(cs_mapRelay)
+ {
+ map<CInv, CDataStream>::iterator mi = mapRelay.find(inv);
+ if (mi != mapRelay.end())
+ pfrom->PushMessage(inv.GetCommand(), (*mi).second);
+ }
+ }
+
+ // Track requests for our stuff
+ CRITICAL_BLOCK(cs_mapRequestCount)
+ {
+ map<uint256, int>::iterator mi = mapRequestCount.find(inv.hash);
+ if (mi != mapRequestCount.end())
+ (*mi).second++;
+ }
+ }
+ }
+
+
+ else if (strCommand == "getblocks")
+ {
+ CBlockLocator locator;
+ uint256 hashStop;
+ vRecv >> locator >> hashStop;
+
+ // Find the last block the caller has in the main chain
+ CBlockIndex* pindex = locator.GetBlockIndex();
+
+ // Send the rest of the chain
+ if (pindex)
+ pindex = pindex->pnext;
+ int nLimit = 500 + locator.GetDistanceBack();
+ printf("getblocks %d to %s limit %d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().substr(0,20).c_str(), nLimit);
+ for (; pindex; pindex = pindex->pnext)
+ {
+ if (pindex->GetBlockHash() == hashStop)
+ {
+ printf(" getblocks stopping at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString().substr(0,20).c_str());
+ break;
+ }
+ pfrom->PushInventory(CInv(MSG_BLOCK, pindex->GetBlockHash()));
+ if (--nLimit <= 0)
+ {
+ // When this block is requested, we'll send an inv that'll make them
+ // getblocks the next batch of inventory.
+ printf(" getblocks stopping at limit %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString().substr(0,20).c_str());
+ pfrom->hashContinue = pindex->GetBlockHash();
+ break;
+ }
+ }
+ }
+
+
+ else if (strCommand == "getheaders")
+ {
+ CBlockLocator locator;
+ uint256 hashStop;
+ vRecv >> locator >> hashStop;
+
+ CBlockIndex* pindex = NULL;
+ if (locator.IsNull())
+ {
+ // If locator is null, return the hashStop block
+ map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashStop);
+ if (mi == mapBlockIndex.end())
+ return true;
+ pindex = (*mi).second;
+ }
+ else
+ {
+ // Find the last block the caller has in the main chain
+ pindex = locator.GetBlockIndex();
+ if (pindex)
+ pindex = pindex->pnext;
+ }
+
+ vector<CBlock> vHeaders;
+ int nLimit = 2000 + locator.GetDistanceBack();
+ printf("getheaders %d to %s limit %d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().substr(0,20).c_str(), nLimit);
+ for (; pindex; pindex = pindex->pnext)
+ {
+ vHeaders.push_back(pindex->GetBlockHeader());
+ if (--nLimit <= 0 || pindex->GetBlockHash() == hashStop)
+ break;
+ }
+ pfrom->PushMessage("headers", vHeaders);
+ }
+
+
+ else if (strCommand == "tx")
+ {
+ vector<uint256> vWorkQueue;
+ CDataStream vMsg(vRecv);
+ CTransaction tx;
+ vRecv >> tx;
+
+ CInv inv(MSG_TX, tx.GetHash());
+ pfrom->AddInventoryKnown(inv);
+
+ bool fMissingInputs = false;
+ if (tx.AcceptToMemoryPool(true, &fMissingInputs))
+ {
+ AddToWalletIfInvolvingMe(tx, NULL, true);
+ RelayMessage(inv, vMsg);
+ mapAlreadyAskedFor.erase(inv);
+ vWorkQueue.push_back(inv.hash);
+
+ // Recursively process any orphan transactions that depended on this one
+ for (int i = 0; i < vWorkQueue.size(); i++)
+ {
+ uint256 hashPrev = vWorkQueue[i];
+ for (multimap<uint256, CDataStream*>::iterator mi = mapOrphanTransactionsByPrev.lower_bound(hashPrev);
+ mi != mapOrphanTransactionsByPrev.upper_bound(hashPrev);
+ ++mi)
+ {
+ const CDataStream& vMsg = *((*mi).second);
+ CTransaction tx;
+ CDataStream(vMsg) >> tx;
+ CInv inv(MSG_TX, tx.GetHash());
+
+ if (tx.AcceptToMemoryPool(true))
+ {
+ printf(" accepted orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str());
+ AddToWalletIfInvolvingMe(tx, NULL, true);
+ RelayMessage(inv, vMsg);
+ mapAlreadyAskedFor.erase(inv);
+ vWorkQueue.push_back(inv.hash);
+ }
+ }
+ }
+
+ BOOST_FOREACH(uint256 hash, vWorkQueue)
+ EraseOrphanTx(hash);
+ }
+ else if (fMissingInputs)
+ {
+ printf("storing orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str());
+ AddOrphanTx(vMsg);
+ }
+ }
+
+
+ else if (strCommand == "block")
+ {
+ CBlock block;
+ vRecv >> block;
+
+ printf("received block %s\n", block.GetHash().ToString().substr(0,20).c_str());
+ // block.print();
+
+ CInv inv(MSG_BLOCK, block.GetHash());
+ pfrom->AddInventoryKnown(inv);
+
+ if (ProcessBlock(pfrom, &block))
+ mapAlreadyAskedFor.erase(inv);
+ }
+
+
+ else if (strCommand == "getaddr")
+ {
+ // Nodes rebroadcast an addr every 24 hours
+ pfrom->vAddrToSend.clear();
+ int64 nSince = GetAdjustedTime() - 3 * 60 * 60; // in the last 3 hours
+ CRITICAL_BLOCK(cs_mapAddresses)
+ {
+ unsigned int nCount = 0;
+ BOOST_FOREACH(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses)
+ {
+ const CAddress& addr = item.second;
+ if (addr.nTime > nSince)
+ nCount++;
+ }
+ BOOST_FOREACH(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses)
+ {
+ const CAddress& addr = item.second;
+ if (addr.nTime > nSince && GetRand(nCount) < 2500)
+ pfrom->PushAddress(addr);
+ }
+ }
+ }
+
+
+ else if (strCommand == "checkorder")
+ {
+ uint256 hashReply;
+ vRecv >> hashReply;
+
+ if (!GetBoolArg("-allowreceivebyip"))
+ {
+ pfrom->PushMessage("reply", hashReply, (int)2, string(""));
+ return true;
+ }
+
+ CWalletTx order;
+ vRecv >> order;
+
+ /// we have a chance to check the order here
+
+ // Keep giving the same key to the same ip until they use it
+ if (!mapReuseKey.count(pfrom->addr.ip))
+ mapReuseKey[pfrom->addr.ip] = GetKeyFromKeyPool();
+
+ // Send back approval of order and pubkey to use
+ CScript scriptPubKey;
+ scriptPubKey << mapReuseKey[pfrom->addr.ip] << OP_CHECKSIG;
+ pfrom->PushMessage("reply", hashReply, (int)0, scriptPubKey);
+ }
+
+
+ else if (strCommand == "submitorder")
+ {
+ uint256 hashReply;
+ vRecv >> hashReply;
+
+ if (!GetBoolArg("-allowreceivebyip"))
+ {
+ pfrom->PushMessage("reply", hashReply, (int)2);
+ return true;
+ }
+
+ CWalletTx wtxNew;
+ vRecv >> wtxNew;
+ wtxNew.fFromMe = false;
+
+ // Broadcast
+ if (!wtxNew.AcceptWalletTransaction())
+ {
+ pfrom->PushMessage("reply", hashReply, (int)1);
+ return error("submitorder AcceptWalletTransaction() failed, returning error 1");
+ }
+ wtxNew.fTimeReceivedIsTxTime = true;
+ AddToWallet(wtxNew);
+ wtxNew.RelayWalletTransaction();
+ mapReuseKey.erase(pfrom->addr.ip);
+
+ // Send back confirmation
+ pfrom->PushMessage("reply", hashReply, (int)0);
+ }
+
+
+ else if (strCommand == "reply")
+ {
+ uint256 hashReply;
+ vRecv >> hashReply;
+
+ CRequestTracker tracker;
+ CRITICAL_BLOCK(pfrom->cs_mapRequests)
+ {
+ map<uint256, CRequestTracker>::iterator mi = pfrom->mapRequests.find(hashReply);
+ if (mi != pfrom->mapRequests.end())
+ {
+ tracker = (*mi).second;
+ pfrom->mapRequests.erase(mi);
+ }
+ }
+ if (!tracker.IsNull())
+ tracker.fn(tracker.param1, vRecv);
+ }
+
+
+ else if (strCommand == "ping")
+ {
+ }
+
+
+ else if (strCommand == "alert")
+ {
+ CAlert alert;
+ vRecv >> alert;
+
+ if (alert.ProcessAlert())
+ {
+ // Relay
+ pfrom->setKnown.insert(alert.GetHash());
+ CRITICAL_BLOCK(cs_vNodes)
+ BOOST_FOREACH(CNode* pnode, vNodes)
+ alert.RelayTo(pnode);
+ }
+ }
+
+
+ else
+ {
+ // Ignore unknown commands for extensibility
+ }
+
+
+ // Update the last seen time for this node's address
+ if (pfrom->fNetworkNode)
+ if (strCommand == "version" || strCommand == "addr" || strCommand == "inv" || strCommand == "getdata" || strCommand == "ping")
+ AddressCurrentlyConnected(pfrom->addr);
+
+
+ return true;
+}
+
+
+
+
+
+
+
+
+
+bool SendMessages(CNode* pto, bool fSendTrickle)
+{
+ CRITICAL_BLOCK(cs_main)
+ {
+ // Don't send anything until we get their version message
+ if (pto->nVersion == 0)
+ return true;
+
+ // Keep-alive ping
+ if (pto->nLastSend && GetTime() - pto->nLastSend > 30 * 60 && pto->vSend.empty())
+ pto->PushMessage("ping");
+
+ // Resend wallet transactions that haven't gotten in a block yet
+ ResendWalletTransactions();
+
+ // Address refresh broadcast
+ static int64 nLastRebroadcast;
+ if (GetTime() - nLastRebroadcast > 24 * 60 * 60)
+ {
+ nLastRebroadcast = GetTime();
+ CRITICAL_BLOCK(cs_vNodes)
+ {
+ BOOST_FOREACH(CNode* pnode, vNodes)
+ {
+ // Periodically clear setAddrKnown to allow refresh broadcasts
+ pnode->setAddrKnown.clear();
+
+ // Rebroadcast our address
+ if (addrLocalHost.IsRoutable() && !fUseProxy)
+ {
+ CAddress addr(addrLocalHost);
+ addr.nTime = GetAdjustedTime();
+ pnode->PushAddress(addr);
+ }
+ }
+ }
+ }
+
+ // Clear out old addresses periodically so it's not too much work at once
+ static int64 nLastClear;
+ if (nLastClear == 0)
+ nLastClear = GetTime();
+ if (GetTime() - nLastClear > 10 * 60 && vNodes.size() >= 3)
+ {
+ nLastClear = GetTime();
+ CRITICAL_BLOCK(cs_mapAddresses)
+ {
+ CAddrDB addrdb;
+ int64 nSince = GetAdjustedTime() - 14 * 24 * 60 * 60;
+ for (map<vector<unsigned char>, CAddress>::iterator mi = mapAddresses.begin();
+ mi != mapAddresses.end();)
+ {
+ const CAddress& addr = (*mi).second;
+ if (addr.nTime < nSince)
+ {
+ if (mapAddresses.size() < 1000 || GetTime() > nLastClear + 20)
+ break;
+ addrdb.EraseAddress(addr);
+ mapAddresses.erase(mi++);
+ }
+ else
+ mi++;
+ }
+ }
+ }
+
+
+ //
+ // Message: addr
+ //
+ if (fSendTrickle)
+ {
+ vector<CAddress> vAddr;
+ vAddr.reserve(pto->vAddrToSend.size());
+ BOOST_FOREACH(const CAddress& addr, pto->vAddrToSend)
+ {
+ // returns true if wasn't already contained in the set
+ if (pto->setAddrKnown.insert(addr).second)
+ {
+ vAddr.push_back(addr);
+ // receiver rejects addr messages larger than 1000
+ if (vAddr.size() >= 1000)
+ {
+ pto->PushMessage("addr", vAddr);
+ vAddr.clear();
+ }
+ }
+ }
+ pto->vAddrToSend.clear();
+ if (!vAddr.empty())
+ pto->PushMessage("addr", vAddr);
+ }
+
+
+ //
+ // Message: inventory
+ //
+ vector<CInv> vInv;
+ vector<CInv> vInvWait;
+ CRITICAL_BLOCK(pto->cs_inventory)
+ {
+ vInv.reserve(pto->vInventoryToSend.size());
+ vInvWait.reserve(pto->vInventoryToSend.size());
+ BOOST_FOREACH(const CInv& inv, pto->vInventoryToSend)
+ {
+ if (pto->setInventoryKnown.count(inv))
+ continue;
+
+ // trickle out tx inv to protect privacy
+ if (inv.type == MSG_TX && !fSendTrickle)
+ {
+ // 1/4 of tx invs blast to all immediately
+ static uint256 hashSalt;
+ if (hashSalt == 0)
+ RAND_bytes((unsigned char*)&hashSalt, sizeof(hashSalt));
+ uint256 hashRand = inv.hash ^ hashSalt;
+ hashRand = Hash(BEGIN(hashRand), END(hashRand));
+ bool fTrickleWait = ((hashRand & 3) != 0);
+
+ // always trickle our own transactions
+ if (!fTrickleWait)
+ {
+ TRY_CRITICAL_BLOCK(cs_mapWallet)
+ {
+ map<uint256, CWalletTx>::iterator mi = mapWallet.find(inv.hash);
+ if (mi != mapWallet.end())
+ {
+ CWalletTx& wtx = (*mi).second;
+ if (wtx.fFromMe)
+ fTrickleWait = true;
+ }
+ }
+ }
+
+ if (fTrickleWait)
+ {
+ vInvWait.push_back(inv);
+ continue;
+ }
+ }
+
+ // returns true if wasn't already contained in the set
+ if (pto->setInventoryKnown.insert(inv).second)
+ {
+ vInv.push_back(inv);
+ if (vInv.size() >= 1000)
+ {
+ pto->PushMessage("inv", vInv);
+ vInv.clear();
+ }
+ }
+ }
+ pto->vInventoryToSend = vInvWait;
+ }
+ if (!vInv.empty())
+ pto->PushMessage("inv", vInv);
+
+
+ //
+ // Message: getdata
+ //
+ vector<CInv> vGetData;
+ int64 nNow = GetTime() * 1000000;
+ CTxDB txdb("r");
+ while (!pto->mapAskFor.empty() && (*pto->mapAskFor.begin()).first <= nNow)
+ {
+ const CInv& inv = (*pto->mapAskFor.begin()).second;
+ if (!AlreadyHave(txdb, inv))
+ {
+ printf("sending getdata: %s\n", inv.ToString().c_str());
+ vGetData.push_back(inv);
+ if (vGetData.size() >= 1000)
+ {
+ pto->PushMessage("getdata", vGetData);
+ vGetData.clear();
+ }
+ }
+ pto->mapAskFor.erase(pto->mapAskFor.begin());
+ }
+ if (!vGetData.empty())
+ pto->PushMessage("getdata", vGetData);
+
+ }
+ return true;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// BitcoinMiner
+//
+
+void GenerateBitcoins(bool fGenerate)
+{
+ if (fGenerateBitcoins != fGenerate)
+ {
+ fGenerateBitcoins = fGenerate;
+ CWalletDB().WriteSetting("fGenerateBitcoins", fGenerateBitcoins);
+ MainFrameRepaint();
+ }
+ if (fGenerateBitcoins)
+ {
+ int nProcessors = boost::thread::hardware_concurrency();
+ printf("%d processors\n", nProcessors);
+ if (nProcessors < 1)
+ nProcessors = 1;
+ if (fLimitProcessors && nProcessors > nLimitProcessors)
+ nProcessors = nLimitProcessors;
+ int nAddThreads = nProcessors - vnThreadsRunning[3];
+ printf("Starting %d BitcoinMiner threads\n", nAddThreads);
+ for (int i = 0; i < nAddThreads; i++)
+ {
+ if (!CreateThread(ThreadBitcoinMiner, NULL))
+ printf("Error: CreateThread(ThreadBitcoinMiner) failed\n");
+ Sleep(10);
+ }
+ }
+}
+
+void ThreadBitcoinMiner(void* parg)
+{
+ try
+ {
+ vnThreadsRunning[3]++;
+ BitcoinMiner();
+ vnThreadsRunning[3]--;
+ }
+ catch (std::exception& e) {
+ vnThreadsRunning[3]--;
+ PrintException(&e, "ThreadBitcoinMiner()");
+ } catch (...) {
+ vnThreadsRunning[3]--;
+ PrintException(NULL, "ThreadBitcoinMiner()");
+ }
+ UIThreadCall(boost::bind(CalledSetStatusBar, "", 0));
+ nHPSTimerStart = 0;
+ if (vnThreadsRunning[3] == 0)
+ dHashesPerSec = 0;
+ printf("ThreadBitcoinMiner exiting, %d threads remaining\n", vnThreadsRunning[3]);
+}
+
+
+int FormatHashBlocks(void* pbuffer, unsigned int len)
+{
+ unsigned char* pdata = (unsigned char*)pbuffer;
+ unsigned int blocks = 1 + ((len + 8) / 64);
+ unsigned char* pend = pdata + 64 * blocks;
+ memset(pdata + len, 0, 64 * blocks - len);
+ pdata[len] = 0x80;
+ unsigned int bits = len * 8;
+ pend[-1] = (bits >> 0) & 0xff;
+ pend[-2] = (bits >> 8) & 0xff;
+ pend[-3] = (bits >> 16) & 0xff;
+ pend[-4] = (bits >> 24) & 0xff;
+ return blocks;
+}
+
+using CryptoPP::ByteReverse;
+
+static const unsigned int pSHA256InitState[8] =
+{0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
+
+inline void SHA256Transform(void* pstate, void* pinput, const void* pinit)
+{
+ memcpy(pstate, pinit, 32);
+ CryptoPP::SHA256::Transform((CryptoPP::word32*)pstate, (CryptoPP::word32*)pinput);
+}
+
+//
+// ScanHash scans nonces looking for a hash with at least some zero bits.
+// It operates on big endian data. Caller does the byte reversing.
+// All input buffers are 16-byte aligned. nNonce is usually preserved
+// between calls, but periodically or if nNonce is 0xffff0000 or above,
+// the block is rebuilt and nNonce starts over at zero.
+//
+unsigned int ScanHash_CryptoPP(char* pmidstate, char* pdata, char* phash1, char* phash, unsigned int& nHashesDone)
+{
+ unsigned int& nNonce = *(unsigned int*)(pdata + 12);
+ for (;;)
+ {
+ // Crypto++ SHA-256
+ // Hash pdata using pmidstate as the starting state into
+ // preformatted buffer phash1, then hash phash1 into phash
+ nNonce++;
+ SHA256Transform(phash1, pdata, pmidstate);
+ SHA256Transform(phash, phash1, pSHA256InitState);
+
+ // Return the nonce if the hash has at least some zero bits,
+ // caller will check if it has enough to reach the target
+ if (((unsigned short*)phash)[14] == 0)
+ return nNonce;
+
+ // If nothing found after trying for a while, return -1
+ if ((nNonce & 0xffff) == 0)
+ {
+ nHashesDone = 0xffff+1;
+ return -1;
+ }
+ }
+}
+
+
+class COrphan
+{
+public:
+ CTransaction* ptx;
+ set<uint256> setDependsOn;
+ double dPriority;
+
+ COrphan(CTransaction* ptxIn)
+ {
+ ptx = ptxIn;
+ dPriority = 0;
+ }
+
+ void print() const
+ {
+ printf("COrphan(hash=%s, dPriority=%.1f)\n", ptx->GetHash().ToString().substr(0,10).c_str(), dPriority);
+ BOOST_FOREACH(uint256 hash, setDependsOn)
+ printf(" setDependsOn %s\n", hash.ToString().substr(0,10).c_str());
+ }
+};
+
+
+CBlock* CreateNewBlock(CReserveKey& reservekey)
+{
+ CBlockIndex* pindexPrev = pindexBest;
+
+ // Create new block
+ auto_ptr<CBlock> pblock(new CBlock());
+ if (!pblock.get())
+ return NULL;
+
+ // Create coinbase tx
+ CTransaction txNew;
+ txNew.vin.resize(1);
+ txNew.vin[0].prevout.SetNull();
+ txNew.vout.resize(1);
+ txNew.vout[0].scriptPubKey << reservekey.GetReservedKey() << OP_CHECKSIG;
+
+ // Add our coinbase tx as first transaction
+ pblock->vtx.push_back(txNew);
+
+ // Collect memory pool transactions into the block
+ int64 nFees = 0;
+ CRITICAL_BLOCK(cs_main)
+ CRITICAL_BLOCK(cs_mapTransactions)
+ {
+ CTxDB txdb("r");
+
+ // Priority order to process transactions
+ list<COrphan> vOrphan; // list memory doesn't move
+ map<uint256, vector<COrphan*> > mapDependers;
+ multimap<double, CTransaction*> mapPriority;
+ for (map<uint256, CTransaction>::iterator mi = mapTransactions.begin(); mi != mapTransactions.end(); ++mi)
+ {
+ CTransaction& tx = (*mi).second;
+ if (tx.IsCoinBase() || !tx.IsFinal())
+ continue;
+
+ COrphan* porphan = NULL;
+ double dPriority = 0;
+ BOOST_FOREACH(const CTxIn& txin, tx.vin)
+ {
+ // Read prev transaction
+ CTransaction txPrev;
+ CTxIndex txindex;
+ if (!txPrev.ReadFromDisk(txdb, txin.prevout, txindex))
+ {
+ // Has to wait for dependencies
+ if (!porphan)
+ {
+ // Use list for automatic deletion
+ vOrphan.push_back(COrphan(&tx));
+ porphan = &vOrphan.back();
+ }
+ mapDependers[txin.prevout.hash].push_back(porphan);
+ porphan->setDependsOn.insert(txin.prevout.hash);
+ continue;
+ }
+ int64 nValueIn = txPrev.vout[txin.prevout.n].nValue;
+
+ // Read block header
+ int nConf = txindex.GetDepthInMainChain();
+
+ dPriority += (double)nValueIn * nConf;
+
+ if (fDebug && GetBoolArg("-printpriority"))
+ printf("priority nValueIn=%-12I64d nConf=%-5d dPriority=%-20.1f\n", nValueIn, nConf, dPriority);
+ }
+
+ // Priority is sum(valuein * age) / txsize
+ dPriority /= ::GetSerializeSize(tx, SER_NETWORK);
+
+ if (porphan)
+ porphan->dPriority = dPriority;
+ else
+ mapPriority.insert(make_pair(-dPriority, &(*mi).second));
+
+ if (fDebug && GetBoolArg("-printpriority"))
+ {
+ printf("priority %-20.1f %s\n%s", dPriority, tx.GetHash().ToString().substr(0,10).c_str(), tx.ToString().c_str());
+ if (porphan)
+ porphan->print();
+ printf("\n");
+ }
+ }
+
+ // Collect transactions into block
+ map<uint256, CTxIndex> mapTestPool;
+ uint64 nBlockSize = 1000;
+ int nBlockSigOps = 100;
+ while (!mapPriority.empty())
+ {
+ // Take highest priority transaction off priority queue
+ double dPriority = -(*mapPriority.begin()).first;
+ CTransaction& tx = *(*mapPriority.begin()).second;
+ mapPriority.erase(mapPriority.begin());
+
+ // Size limits
+ unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK);
+ if (nBlockSize + nTxSize >= MAX_BLOCK_SIZE_GEN)
+ continue;
+ int nTxSigOps = tx.GetSigOpCount();
+ if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)
+ continue;
+
+ // Transaction fee required depends on block size
+ bool fAllowFree = (nBlockSize + nTxSize < 4000 || CTransaction::AllowFree(dPriority));
+ int64 nMinFee = tx.GetMinFee(nBlockSize, fAllowFree);
+
+ // Connecting shouldn't fail due to dependency on other memory pool transactions
+ // because we're already processing them in order of dependency
+ map<uint256, CTxIndex> mapTestPoolTmp(mapTestPool);
+ if (!tx.ConnectInputs(txdb, mapTestPoolTmp, CDiskTxPos(1,1,1), pindexPrev, nFees, false, true, nMinFee))
+ continue;
+ swap(mapTestPool, mapTestPoolTmp);
+
+ // Added
+ pblock->vtx.push_back(tx);
+ nBlockSize += nTxSize;
+ nBlockSigOps += nTxSigOps;
+
+ // Add transactions that depend on this one to the priority queue
+ uint256 hash = tx.GetHash();
+ if (mapDependers.count(hash))
+ {
+ BOOST_FOREACH(COrphan* porphan, mapDependers[hash])
+ {
+ if (!porphan->setDependsOn.empty())
+ {
+ porphan->setDependsOn.erase(hash);
+ if (porphan->setDependsOn.empty())
+ mapPriority.insert(make_pair(-porphan->dPriority, porphan->ptx));
+ }
+ }
+ }
+ }
+ }
+ pblock->vtx[0].vout[0].nValue = GetBlockValue(pindexPrev->nHeight+1, nFees);
+
+ // Fill in header
+ pblock->hashPrevBlock = pindexPrev->GetBlockHash();
+ pblock->hashMerkleRoot = pblock->BuildMerkleTree();
+ pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
+ pblock->nBits = GetNextWorkRequired(pindexPrev);
+ pblock->nNonce = 0;
+
+ return pblock.release();
+}
+
+
+void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce, int64& nPrevTime)
+{
+ // Update nExtraNonce
+ int64 nNow = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
+ if (++nExtraNonce >= 0x7f && nNow > nPrevTime+1)
+ {
+ nExtraNonce = 1;
+ nPrevTime = nNow;
+ }
+ pblock->vtx[0].vin[0].scriptSig = CScript() << pblock->nBits << CBigNum(nExtraNonce);
+ pblock->hashMerkleRoot = pblock->BuildMerkleTree();
+}
+
+
+void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1)
+{
+ //
+ // Prebuild hash buffers
+ //
+ struct
+ {
+ struct unnamed2
+ {
+ int nVersion;
+ uint256 hashPrevBlock;
+ uint256 hashMerkleRoot;
+ unsigned int nTime;
+ unsigned int nBits;
+ unsigned int nNonce;
+ }
+ block;
+ unsigned char pchPadding0[64];
+ uint256 hash1;
+ unsigned char pchPadding1[64];
+ }
+ tmp;
+ memset(&tmp, 0, sizeof(tmp));
+
+ tmp.block.nVersion = pblock->nVersion;
+ tmp.block.hashPrevBlock = pblock->hashPrevBlock;
+ tmp.block.hashMerkleRoot = pblock->hashMerkleRoot;
+ tmp.block.nTime = pblock->nTime;
+ tmp.block.nBits = pblock->nBits;
+ tmp.block.nNonce = pblock->nNonce;
+
+ FormatHashBlocks(&tmp.block, sizeof(tmp.block));
+ FormatHashBlocks(&tmp.hash1, sizeof(tmp.hash1));
+
+ // Byte swap all the input buffer
+ for (int i = 0; i < sizeof(tmp)/4; i++)
+ ((unsigned int*)&tmp)[i] = ByteReverse(((unsigned int*)&tmp)[i]);
+
+ // Precalc the first half of the first hash, which stays constant
+ SHA256Transform(pmidstate, &tmp.block, pSHA256InitState);
+
+ memcpy(pdata, &tmp.block, 128);
+ memcpy(phash1, &tmp.hash1, 64);
+}
+
+
+bool CheckWork(CBlock* pblock, CReserveKey& reservekey)
+{
+ uint256 hash = pblock->GetHash();
+ uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
+
+ if (hash > hashTarget)
+ return false;
+
+ //// debug print
+ printf("BitcoinMiner:\n");
+ printf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex().c_str(), hashTarget.GetHex().c_str());
+ pblock->print();
+ printf("%s ", DateTimeStrFormat("%x %H:%M", GetTime()).c_str());
+ printf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue).c_str());
+
+ // Found a solution
+ CRITICAL_BLOCK(cs_main)
+ {
+ if (pblock->hashPrevBlock != hashBestChain)
+ return error("BitcoinMiner : generated block is stale");
+
+ // Remove key from key pool
+ reservekey.KeepKey();
+
+ // Track how many getdata requests this block gets
+ CRITICAL_BLOCK(cs_mapRequestCount)
+ mapRequestCount[pblock->GetHash()] = 0;
+
+ // Process this block the same as if we had received it from another node
+ if (!ProcessBlock(NULL, pblock))
+ return error("BitcoinMiner : ProcessBlock, block not accepted");
+ }
+
+ Sleep(2000);
+ return true;
+}
+
+
+void BitcoinMiner()
+{
+ printf("BitcoinMiner started\n");
+ SetThreadPriority(THREAD_PRIORITY_LOWEST);
+
+ // Each thread has its own key and counter
+ CReserveKey reservekey;
+ unsigned int nExtraNonce = 0;
+ int64 nPrevTime = 0;
+
+ while (fGenerateBitcoins)
+ {
+ if (AffinityBugWorkaround(ThreadBitcoinMiner))
+ return;
+ if (fShutdown)
+ return;
+ while (vNodes.empty() || IsInitialBlockDownload())
+ {
+ Sleep(1000);
+ if (fShutdown)
+ return;
+ if (!fGenerateBitcoins)
+ return;
+ }
+
+
+ //
+ // Create new block
+ //
+ unsigned int nTransactionsUpdatedLast = nTransactionsUpdated;
+ CBlockIndex* pindexPrev = pindexBest;
+
+ auto_ptr<CBlock> pblock(CreateNewBlock(reservekey));
+ if (!pblock.get())
+ return;
+ IncrementExtraNonce(pblock.get(), pindexPrev, nExtraNonce, nPrevTime);
+
+ printf("Running BitcoinMiner with %d transactions in block\n", pblock->vtx.size());
+
+
+ //
+ // Prebuild hash buffers
+ //
+ char pmidstatebuf[32+16]; char* pmidstate = alignup<16>(pmidstatebuf);
+ char pdatabuf[128+16]; char* pdata = alignup<16>(pdatabuf);
+ char phash1buf[64+16]; char* phash1 = alignup<16>(phash1buf);
+
+ FormatHashBuffers(pblock.get(), pmidstate, pdata, phash1);
+
+ unsigned int& nBlockTime = *(unsigned int*)(pdata + 64 + 4);
+ unsigned int& nBlockNonce = *(unsigned int*)(pdata + 64 + 12);
+
+
+ //
+ // Search
+ //
+ int64 nStart = GetTime();
+ uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
+ uint256 hashbuf[2];
+ uint256& hash = *alignup<16>(hashbuf);
+ loop
+ {
+ unsigned int nHashesDone = 0;
+ unsigned int nNonceFound;
+
+ // Crypto++ SHA-256
+ nNonceFound = ScanHash_CryptoPP(pmidstate, pdata + 64, phash1,
+ (char*)&hash, nHashesDone);
+
+ // Check if something found
+ if (nNonceFound != -1)
+ {
+ for (int i = 0; i < sizeof(hash)/4; i++)
+ ((unsigned int*)&hash)[i] = ByteReverse(((unsigned int*)&hash)[i]);
+
+ if (hash <= hashTarget)
+ {
+ // Found a solution
+ pblock->nNonce = ByteReverse(nNonceFound);
+ assert(hash == pblock->GetHash());
+
+ SetThreadPriority(THREAD_PRIORITY_NORMAL);
+ CheckWork(pblock.get(), reservekey);
+ SetThreadPriority(THREAD_PRIORITY_LOWEST);
+ break;
+ }
+ }
+
+ // Meter hashes/sec
+ static int64 nHashCounter;
+ if (nHPSTimerStart == 0)
+ {
+ nHPSTimerStart = GetTimeMillis();
+ nHashCounter = 0;
+ }
+ else
+ nHashCounter += nHashesDone;
+ if (GetTimeMillis() - nHPSTimerStart > 4000)
+ {
+ static CCriticalSection cs;
+ CRITICAL_BLOCK(cs)
+ {
+ if (GetTimeMillis() - nHPSTimerStart > 4000)
+ {
+ dHashesPerSec = 1000.0 * nHashCounter / (GetTimeMillis() - nHPSTimerStart);
+ nHPSTimerStart = GetTimeMillis();
+ nHashCounter = 0;
+ string strStatus = strprintf(" %.0f khash/s", dHashesPerSec/1000.0);
+ UIThreadCall(boost::bind(CalledSetStatusBar, strStatus, 0));
+ static int64 nLogTime;
+ if (GetTime() - nLogTime > 30 * 60)
+ {
+ nLogTime = GetTime();
+ printf("%s ", DateTimeStrFormat("%x %H:%M", GetTime()).c_str());
+ printf("hashmeter %3d CPUs %6.0f khash/s\n", vnThreadsRunning[3], dHashesPerSec/1000.0);
+ }
+ }
+ }
+ }
+
+ // Check for stop or if block needs to be rebuilt
+ if (fShutdown)
+ return;
+ if (!fGenerateBitcoins)
+ return;
+ if (fLimitProcessors && vnThreadsRunning[3] > nLimitProcessors)
+ return;
+ if (vNodes.empty())
+ break;
+ if (nBlockNonce >= 0xffff0000)
+ break;
+ if (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60)
+ break;
+ if (pindexPrev != pindexBest)
+ break;
+
+ // Update nTime every few seconds
+ pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
+ nBlockTime = ByteReverse(pblock->nTime);
+ }
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Actions
+//
+
+
+int64 GetBalance()
+{
+ int64 nStart = GetTimeMillis();
+
+ int64 nTotal = 0;
+ CRITICAL_BLOCK(cs_mapWallet)
+ {
+ for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ {
+ CWalletTx* pcoin = &(*it).second;
+ if (!pcoin->IsFinal() || !pcoin->IsConfirmed())
+ continue;
+ nTotal += pcoin->GetAvailableCredit();
+ }
+ }
+
+ //printf("GetBalance() %"PRI64d"ms\n", GetTimeMillis() - nStart);
+ return nTotal;
+}
+
+
+bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set<pair<CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet)
+{
+ setCoinsRet.clear();
+ nValueRet = 0;
+
+ // List of values less than target
+ pair<int64, pair<CWalletTx*,unsigned int> > coinLowestLarger;
+ coinLowestLarger.first = INT64_MAX;
+ coinLowestLarger.second.first = NULL;
+ vector<pair<int64, pair<CWalletTx*,unsigned int> > > vValue;
+ int64 nTotalLower = 0;
+
+ CRITICAL_BLOCK(cs_mapWallet)
+ {
+ vector<CWalletTx*> vCoins;
+ vCoins.reserve(mapWallet.size());
+ for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ vCoins.push_back(&(*it).second);
+ random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt);
+
+ BOOST_FOREACH(CWalletTx* pcoin, vCoins)
+ {
+ if (!pcoin->IsFinal() || !pcoin->IsConfirmed())
+ continue;
+
+ if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
+ continue;
+
+ int nDepth = pcoin->GetDepthInMainChain();
+ if (nDepth < (pcoin->IsFromMe() ? nConfMine : nConfTheirs))
+ continue;
+
+ for (int i = 0; i < pcoin->vout.size(); i++)
+ {
+ if (pcoin->IsSpent(i) || !pcoin->vout[i].IsMine())
+ continue;
+
+ int64 n = pcoin->vout[i].nValue;
+
+ if (n <= 0)
+ continue;
+
+ pair<int64,pair<CWalletTx*,unsigned int> > coin = make_pair(n,make_pair(pcoin,i));
+
+ if (n == nTargetValue)
+ {
+ setCoinsRet.insert(coin.second);
+ nValueRet += coin.first;
+ return true;
+ }
+ else if (n < nTargetValue + CENT)
+ {
+ vValue.push_back(coin);
+ nTotalLower += n;
+ }
+ else if (n < coinLowestLarger.first)
+ {
+ coinLowestLarger = coin;
+ }
+ }
+ }
+ }
+
+ if (nTotalLower == nTargetValue || nTotalLower == nTargetValue + CENT)
+ {
+ for (int i = 0; i < vValue.size(); ++i)
+ {
+ setCoinsRet.insert(vValue[i].second);
+ nValueRet += vValue[i].first;
+ }
+ return true;
+ }
+
+ if (nTotalLower < nTargetValue + (coinLowestLarger.second.first ? CENT : 0))
+ {
+ if (coinLowestLarger.second.first == NULL)
+ return false;
+ setCoinsRet.insert(coinLowestLarger.second);
+ nValueRet += coinLowestLarger.first;
+ return true;
+ }
+
+ if (nTotalLower >= nTargetValue + CENT)
+ nTargetValue += CENT;
+
+ // Solve subset sum by stochastic approximation
+ sort(vValue.rbegin(), vValue.rend());
+ vector<char> vfIncluded;
+ vector<char> vfBest(vValue.size(), true);
+ int64 nBest = nTotalLower;
+
+ for (int nRep = 0; nRep < 1000 && nBest != nTargetValue; nRep++)
+ {
+ vfIncluded.assign(vValue.size(), false);
+ int64 nTotal = 0;
+ bool fReachedTarget = false;
+ for (int nPass = 0; nPass < 2 && !fReachedTarget; nPass++)
+ {
+ for (int i = 0; i < vValue.size(); i++)
+ {
+ if (nPass == 0 ? rand() % 2 : !vfIncluded[i])
+ {
+ nTotal += vValue[i].first;
+ vfIncluded[i] = true;
+ if (nTotal >= nTargetValue)
+ {
+ fReachedTarget = true;
+ if (nTotal < nBest)
+ {
+ nBest = nTotal;
+ vfBest = vfIncluded;
+ }
+ nTotal -= vValue[i].first;
+ vfIncluded[i] = false;
+ }
+ }
+ }
+ }
+ }
+
+ // If the next larger is still closer, return it
+ if (coinLowestLarger.second.first && coinLowestLarger.first - nTargetValue <= nBest - nTargetValue)
+ {
+ setCoinsRet.insert(coinLowestLarger.second);
+ nValueRet += coinLowestLarger.first;
+ }
+ else {
+ for (int i = 0; i < vValue.size(); i++)
+ if (vfBest[i])
+ {
+ setCoinsRet.insert(vValue[i].second);
+ nValueRet += vValue[i].first;
+ }
+
+ //// debug print
+ printf("SelectCoins() best subset: ");
+ for (int i = 0; i < vValue.size(); i++)
+ if (vfBest[i])
+ printf("%s ", FormatMoney(vValue[i].first).c_str());
+ printf("total %s\n", FormatMoney(nBest).c_str());
+ }
+
+ return true;
+}
+
+bool SelectCoins(int64 nTargetValue, set<pair<CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet)
+{
+ return (SelectCoinsMinConf(nTargetValue, 1, 6, setCoinsRet, nValueRet) ||
+ SelectCoinsMinConf(nTargetValue, 1, 1, setCoinsRet, nValueRet) ||
+ SelectCoinsMinConf(nTargetValue, 0, 1, setCoinsRet, nValueRet));
+}
+
+
+
+
+bool CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet)
+{
+ int64 nValue = 0;
+ BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend)
+ {
+ if (nValue < 0)
+ return false;
+ nValue += s.second;
+ }
+ if (vecSend.empty() || nValue < 0)
+ return false;
+
+ CRITICAL_BLOCK(cs_main)
+ {
+ // txdb must be opened before the mapWallet lock
+ CTxDB txdb("r");
+ CRITICAL_BLOCK(cs_mapWallet)
+ {
+ nFeeRet = nTransactionFee;
+ loop
+ {
+ wtxNew.vin.clear();
+ wtxNew.vout.clear();
+ wtxNew.fFromMe = true;
+
+ int64 nTotalValue = nValue + nFeeRet;
+ double dPriority = 0;
+ // vouts to the payees
+ BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend)
+ wtxNew.vout.push_back(CTxOut(s.second, s.first));
+
+ // Choose coins to use
+ set<pair<CWalletTx*,unsigned int> > setCoins;
+ int64 nValueIn = 0;
+ if (!SelectCoins(nTotalValue, setCoins, nValueIn))
+ return false;
+ BOOST_FOREACH(PAIRTYPE(CWalletTx*, unsigned int) pcoin, setCoins)
+ {
+ int64 nCredit = pcoin.first->vout[pcoin.second].nValue;
+ dPriority += (double)nCredit * pcoin.first->GetDepthInMainChain();
+ }
+
+ // Fill a vout back to self with any change
+ int64 nChange = nValueIn - nTotalValue;
+ if (nChange >= CENT)
+ {
+ // Note: We use a new key here to keep it from being obvious which side is the change.
+ // The drawback is that by not reusing a previous key, the change may be lost if a
+ // backup is restored, if the backup doesn't have the new private key for the change.
+ // If we reused the old key, it would be possible to add code to look for and
+ // rediscover unknown transactions that were written with keys of ours to recover
+ // post-backup change.
+
+ // Reserve a new key pair from key pool
+ vector<unsigned char> vchPubKey = reservekey.GetReservedKey();
+ assert(mapKeys.count(vchPubKey));
+
+ // Fill a vout to ourself, using same address type as the payment
+ CScript scriptChange;
+ if (vecSend[0].first.GetBitcoinAddressHash160() != 0)
+ scriptChange.SetBitcoinAddress(vchPubKey);
+ else
+ scriptChange << vchPubKey << OP_CHECKSIG;
+
+ // Insert change txn at random position:
+ vector<CTxOut>::iterator position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size());
+ wtxNew.vout.insert(position, CTxOut(nChange, scriptChange));
+ }
+ else
+ reservekey.ReturnKey();
+
+ // Fill vin
+ BOOST_FOREACH(const PAIRTYPE(CWalletTx*,unsigned int)& coin, setCoins)
+ wtxNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second));
+
+ // Sign
+ int nIn = 0;
+ BOOST_FOREACH(const PAIRTYPE(CWalletTx*,unsigned int)& coin, setCoins)
+ if (!SignSignature(*coin.first, wtxNew, nIn++))
+ return false;
+
+ // Limit size
+ unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK);
+ if (nBytes >= MAX_BLOCK_SIZE_GEN/5)
+ return false;
+ dPriority /= nBytes;
+
+ // Check that enough fee is included
+ int64 nPayFee = nTransactionFee * (1 + (int64)nBytes / 1000);
+ bool fAllowFree = CTransaction::AllowFree(dPriority);
+ int64 nMinFee = wtxNew.GetMinFee(1, fAllowFree);
+ if (nFeeRet < max(nPayFee, nMinFee))
+ {
+ nFeeRet = max(nPayFee, nMinFee);
+ continue;
+ }
+
+ // Fill vtxPrev by copying from previous transactions vtxPrev
+ wtxNew.AddSupportingTransactions(txdb);
+ wtxNew.fTimeReceivedIsTxTime = true;
+
+ break;
+ }
+ }
+ }
+ return true;
+}
+
+bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet)
+{
+ vector< pair<CScript, int64> > vecSend;
+ vecSend.push_back(make_pair(scriptPubKey, nValue));
+ return CreateTransaction(vecSend, wtxNew, reservekey, nFeeRet);
+}
+
+// Call after CreateTransaction unless you want to abort
+bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
+{
+ CRITICAL_BLOCK(cs_main)
+ {
+ printf("CommitTransaction:\n%s", wtxNew.ToString().c_str());
+ CRITICAL_BLOCK(cs_mapWallet)
+ {
+ // This is only to keep the database open to defeat the auto-flush for the
+ // duration of this scope. This is the only place where this optimization
+ // maybe makes sense; please don't do it anywhere else.
+ CWalletDB walletdb("r");
+
+ // Take key pair from key pool so it won't be used again
+ reservekey.KeepKey();
+
+ // Add tx to wallet, because if it has change it's also ours,
+ // otherwise just for transaction history.
+ AddToWallet(wtxNew);
+
+ // Mark old coins as spent
+ set<CWalletTx*> setCoins;
+ BOOST_FOREACH(const CTxIn& txin, wtxNew.vin)
+ {
+ CWalletTx &pcoin = mapWallet[txin.prevout.hash];
+ pcoin.MarkSpent(txin.prevout.n);
+ pcoin.WriteToDisk();
+ vWalletUpdated.push_back(pcoin.GetHash());
+ }
+ }
+
+ // Track how many getdata requests our transaction gets
+ CRITICAL_BLOCK(cs_mapRequestCount)
+ mapRequestCount[wtxNew.GetHash()] = 0;
+
+ // Broadcast
+ if (!wtxNew.AcceptToMemoryPool())
+ {
+ // This must not fail. The transaction has already been signed and recorded.
+ printf("CommitTransaction() : Error: Transaction not valid");
+ return false;
+ }
+ wtxNew.RelayWalletTransaction();
+ }
+ MainFrameRepaint();
+ return true;
+}
+
+
+
+
+// requires cs_main lock
+string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee)
+{
+ CReserveKey reservekey;
+ int64 nFeeRequired;
+ if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired))
+ {
+ string strError;
+ if (nValue + nFeeRequired > GetBalance())
+ strError = strprintf(_("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds "), FormatMoney(nFeeRequired).c_str());
+ else
+ strError = _("Error: Transaction creation failed ");
+ printf("SendMoney() : %s", strError.c_str());
+ return strError;
+ }
+
+ if (fAskFee && !ThreadSafeAskFee(nFeeRequired, _("Sending..."), NULL))
+ return "ABORTED";
+
+ if (!CommitTransaction(wtxNew, reservekey))
+ return _("Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.");
+
+ MainFrameRepaint();
+ return "";
+}
+
+
+
+// requires cs_main lock
+string SendMoneyToBitcoinAddress(string strAddress, int64 nValue, CWalletTx& wtxNew, bool fAskFee)
+{
+ // Check amount
+ if (nValue <= 0)
+ return _("Invalid amount");
+ if (nValue + nTransactionFee > GetBalance())
+ return _("Insufficient funds");
+
+ // Parse bitcoin address
+ CScript scriptPubKey;
+ if (!scriptPubKey.SetBitcoinAddress(strAddress))
+ return _("Invalid bitcoin address");
+
+ return SendMoney(scriptPubKey, nValue, wtxNew, fAskFee);
+}
diff --git a/core/src/net.cpp b/core/src/net.cpp
new file mode 100644
index 0000000000..4f489fdb57
--- /dev/null
+++ b/core/src/net.cpp
@@ -0,0 +1,1665 @@
+// 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.
+
+#include "headers.h"
+
+#ifdef USE_UPNP
+#include <miniupnpc/miniwget.h>
+#include <miniupnpc/miniupnpc.h>
+#include <miniupnpc/upnpcommands.h>
+#include <miniupnpc/upnperrors.h>
+#endif
+
+using namespace std;
+using namespace boost;
+
+static const int MAX_OUTBOUND_CONNECTIONS = 8;
+
+void ThreadMessageHandler2(void* parg);
+void ThreadSocketHandler2(void* parg);
+void ThreadOpenConnections2(void* parg);
+#ifdef USE_UPNP
+void ThreadMapPort2(void* parg);
+#endif
+bool OpenNetworkConnection(const CAddress& addrConnect);
+
+
+
+
+
+//
+// Global state variables
+//
+bool fClient = false;
+bool fAllowDNS = false;
+uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK);
+CAddress addrLocalHost("0.0.0.0", 0, false, nLocalServices);
+CNode* pnodeLocalHost = NULL;
+uint64 nLocalHostNonce = 0;
+array<int, 10> vnThreadsRunning;
+SOCKET hListenSocket = INVALID_SOCKET;
+
+vector<CNode*> vNodes;
+CCriticalSection cs_vNodes;
+map<vector<unsigned char>, CAddress> mapAddresses;
+CCriticalSection cs_mapAddresses;
+map<CInv, CDataStream> mapRelay;
+deque<pair<int64, CInv> > vRelayExpiration;
+CCriticalSection cs_mapRelay;
+map<CInv, int64> mapAlreadyAskedFor;
+
+// Settings
+int fUseProxy = false;
+CAddress addrProxy("127.0.0.1",9050);
+
+
+
+
+
+void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd)
+{
+ // Filter out duplicate requests
+ if (pindexBegin == pindexLastGetBlocksBegin && hashEnd == hashLastGetBlocksEnd)
+ return;
+ pindexLastGetBlocksBegin = pindexBegin;
+ hashLastGetBlocksEnd = hashEnd;
+
+ PushMessage("getblocks", CBlockLocator(pindexBegin), hashEnd);
+}
+
+
+
+
+
+bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet)
+{
+ hSocketRet = INVALID_SOCKET;
+
+ SOCKET hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (hSocket == INVALID_SOCKET)
+ return false;
+#ifdef BSD
+ int set = 1;
+ setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int));
+#endif
+
+ bool fRoutable = !(addrConnect.GetByte(3) == 10 || (addrConnect.GetByte(3) == 192 && addrConnect.GetByte(2) == 168));
+ bool fProxy = (fUseProxy && fRoutable);
+ struct sockaddr_in sockaddr = (fProxy ? addrProxy.GetSockAddr() : addrConnect.GetSockAddr());
+
+ if (connect(hSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR)
+ {
+ closesocket(hSocket);
+ return false;
+ }
+
+ if (fProxy)
+ {
+ printf("proxy connecting %s\n", addrConnect.ToString().c_str());
+ char pszSocks4IP[] = "\4\1\0\0\0\0\0\0user";
+ memcpy(pszSocks4IP + 2, &addrConnect.port, 2);
+ memcpy(pszSocks4IP + 4, &addrConnect.ip, 4);
+ char* pszSocks4 = pszSocks4IP;
+ int nSize = sizeof(pszSocks4IP);
+
+ int ret = send(hSocket, pszSocks4, nSize, MSG_NOSIGNAL);
+ if (ret != nSize)
+ {
+ closesocket(hSocket);
+ return error("Error sending to proxy");
+ }
+ char pchRet[8];
+ if (recv(hSocket, pchRet, 8, 0) != 8)
+ {
+ closesocket(hSocket);
+ return error("Error reading proxy response");
+ }
+ if (pchRet[1] != 0x5a)
+ {
+ closesocket(hSocket);
+ if (pchRet[1] != 0x5b)
+ printf("ERROR: Proxy returned error %d\n", pchRet[1]);
+ return false;
+ }
+ printf("proxy connected %s\n", addrConnect.ToString().c_str());
+ }
+
+ hSocketRet = hSocket;
+ return true;
+}
+
+// portDefault is in host order
+bool Lookup(const char *pszName, vector<CAddress>& vaddr, int nServices, int nMaxSolutions, bool fAllowLookup, int portDefault, bool fAllowPort)
+{
+ vaddr.clear();
+ int port = portDefault;
+ char psz[256];
+ char *pszHost = psz;
+ strlcpy(psz, pszName, sizeof(psz));
+ if (fAllowPort)
+ {
+ char* pszColon = strrchr(psz+1,':');
+ char *pszPortEnd = NULL;
+ int portParsed = pszColon ? strtoul(pszColon+1, &pszPortEnd, 10) : 0;
+ if (pszColon && pszPortEnd && pszPortEnd[0] == 0)
+ {
+ if (psz[0] == '[' && pszColon[-1] == ']')
+ {
+ // Future: enable IPv6 colon-notation inside []
+ pszHost = psz+1;
+ pszColon[-1] = 0;
+ }
+ else
+ pszColon[0] = 0;
+ port = portParsed;
+ if (port < 0 || port > USHRT_MAX)
+ port = USHRT_MAX;
+ }
+ }
+
+ struct in_addr addrIP;
+ if (inet_aton(pszHost, &addrIP))
+ {
+ // valid IP address passed
+ vaddr.push_back(CAddress(addrIP.s_addr, port, nServices));
+ return true;
+ }
+
+ if (!fAllowLookup)
+ return false;
+
+ struct hostent* phostent = gethostbyname(pszHost);
+ if (!phostent)
+ return false;
+
+ if (phostent->h_addrtype != AF_INET)
+ return false;
+
+ char** ppAddr = phostent->h_addr_list;
+ while (*ppAddr != NULL && vaddr.size() != nMaxSolutions)
+ {
+ CAddress addr(((struct in_addr*)ppAddr[0])->s_addr, port, nServices);
+ if (addr.IsValid())
+ vaddr.push_back(addr);
+ ppAddr++;
+ }
+
+ return (vaddr.size() > 0);
+}
+
+// portDefault is in host order
+bool Lookup(const char *pszName, CAddress& addr, int nServices, bool fAllowLookup, int portDefault, bool fAllowPort)
+{
+ vector<CAddress> vaddr;
+ bool fRet = Lookup(pszName, vaddr, nServices, 1, fAllowLookup, portDefault, fAllowPort);
+ if (fRet)
+ addr = vaddr[0];
+ return fRet;
+}
+
+bool GetMyExternalIP2(const CAddress& addrConnect, const char* pszGet, const char* pszKeyword, unsigned int& ipRet)
+{
+ SOCKET hSocket;
+ if (!ConnectSocket(addrConnect, hSocket))
+ return error("GetMyExternalIP() : connection to %s failed", addrConnect.ToString().c_str());
+
+ send(hSocket, pszGet, strlen(pszGet), MSG_NOSIGNAL);
+
+ string strLine;
+ while (RecvLine(hSocket, strLine))
+ {
+ if (strLine.empty()) // HTTP response is separated from headers by blank line
+ {
+ loop
+ {
+ if (!RecvLine(hSocket, strLine))
+ {
+ closesocket(hSocket);
+ return false;
+ }
+ if (pszKeyword == NULL)
+ break;
+ if (strLine.find(pszKeyword) != -1)
+ {
+ strLine = strLine.substr(strLine.find(pszKeyword) + strlen(pszKeyword));
+ break;
+ }
+ }
+ closesocket(hSocket);
+ if (strLine.find("<") != -1)
+ strLine = strLine.substr(0, strLine.find("<"));
+ strLine = strLine.substr(strspn(strLine.c_str(), " \t\n\r"));
+ while (strLine.size() > 0 && isspace(strLine[strLine.size()-1]))
+ strLine.resize(strLine.size()-1);
+ CAddress addr(strLine,0,true);
+ printf("GetMyExternalIP() received [%s] %s\n", strLine.c_str(), addr.ToString().c_str());
+ if (addr.ip == 0 || addr.ip == INADDR_NONE || !addr.IsRoutable())
+ return false;
+ ipRet = addr.ip;
+ return true;
+ }
+ }
+ closesocket(hSocket);
+ return error("GetMyExternalIP() : connection closed");
+}
+
+// We now get our external IP from the IRC server first and only use this as a backup
+bool GetMyExternalIP(unsigned int& ipRet)
+{
+ CAddress addrConnect;
+ const char* pszGet;
+ const char* pszKeyword;
+
+ if (fUseProxy)
+ return false;
+
+ for (int nLookup = 0; nLookup <= 1; nLookup++)
+ for (int nHost = 1; nHost <= 2; nHost++)
+ {
+ // We should be phasing out our use of sites like these. If we need
+ // replacements, we should ask for volunteers to put this simple
+ // php file on their webserver that prints the client IP:
+ // <?php echo $_SERVER["REMOTE_ADDR"]; ?>
+ if (nHost == 1)
+ {
+ addrConnect = CAddress("91.198.22.70",80); // checkip.dyndns.org
+
+ if (nLookup == 1)
+ {
+ CAddress addrIP("checkip.dyndns.org", 80, true);
+ if (addrIP.IsValid())
+ addrConnect = addrIP;
+ }
+
+ pszGet = "GET / HTTP/1.1\r\n"
+ "Host: checkip.dyndns.org\r\n"
+ "User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)\r\n"
+ "Connection: close\r\n"
+ "\r\n";
+
+ pszKeyword = "Address:";
+ }
+ else if (nHost == 2)
+ {
+ addrConnect = CAddress("74.208.43.192", 80); // www.showmyip.com
+
+ if (nLookup == 1)
+ {
+ CAddress addrIP("www.showmyip.com", 80, true);
+ if (addrIP.IsValid())
+ addrConnect = addrIP;
+ }
+
+ pszGet = "GET /simple/ HTTP/1.1\r\n"
+ "Host: www.showmyip.com\r\n"
+ "User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)\r\n"
+ "Connection: close\r\n"
+ "\r\n";
+
+ pszKeyword = NULL; // Returns just IP address
+ }
+
+ if (GetMyExternalIP2(addrConnect, pszGet, pszKeyword, ipRet))
+ return true;
+ }
+
+ return false;
+}
+
+void ThreadGetMyExternalIP(void* parg)
+{
+ // Wait for IRC to get it first
+ if (!GetBoolArg("-noirc"))
+ {
+ for (int i = 0; i < 2 * 60; i++)
+ {
+ Sleep(1000);
+ if (fGotExternalIP || fShutdown)
+ return;
+ }
+ }
+
+ // Fallback in case IRC fails to get it
+ if (GetMyExternalIP(addrLocalHost.ip))
+ {
+ printf("GetMyExternalIP() returned %s\n", addrLocalHost.ToStringIP().c_str());
+ if (addrLocalHost.IsRoutable())
+ {
+ // If we already connected to a few before we had our IP, go back and addr them.
+ // setAddrKnown automatically filters any duplicate sends.
+ CAddress addr(addrLocalHost);
+ addr.nTime = GetAdjustedTime();
+ CRITICAL_BLOCK(cs_vNodes)
+ BOOST_FOREACH(CNode* pnode, vNodes)
+ pnode->PushAddress(addr);
+ }
+ }
+}
+
+
+
+
+
+bool AddAddress(CAddress addr, int64 nTimePenalty)
+{
+ if (!addr.IsRoutable())
+ return false;
+ if (addr.ip == addrLocalHost.ip)
+ return false;
+ addr.nTime = max((int64)0, (int64)addr.nTime - nTimePenalty);
+ CRITICAL_BLOCK(cs_mapAddresses)
+ {
+ map<vector<unsigned char>, CAddress>::iterator it = mapAddresses.find(addr.GetKey());
+ if (it == mapAddresses.end())
+ {
+ // New address
+ printf("AddAddress(%s)\n", addr.ToString().c_str());
+ mapAddresses.insert(make_pair(addr.GetKey(), addr));
+ CAddrDB().WriteAddress(addr);
+ return true;
+ }
+ else
+ {
+ bool fUpdated = false;
+ CAddress& addrFound = (*it).second;
+ if ((addrFound.nServices | addr.nServices) != addrFound.nServices)
+ {
+ // Services have been added
+ addrFound.nServices |= addr.nServices;
+ fUpdated = true;
+ }
+ bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60);
+ int64 nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60);
+ if (addrFound.nTime < addr.nTime - nUpdateInterval)
+ {
+ // Periodically update most recently seen time
+ addrFound.nTime = addr.nTime;
+ fUpdated = true;
+ }
+ if (fUpdated)
+ CAddrDB().WriteAddress(addrFound);
+ }
+ }
+ return false;
+}
+
+void AddressCurrentlyConnected(const CAddress& addr)
+{
+ CRITICAL_BLOCK(cs_mapAddresses)
+ {
+ // Only if it's been published already
+ map<vector<unsigned char>, CAddress>::iterator it = mapAddresses.find(addr.GetKey());
+ if (it != mapAddresses.end())
+ {
+ CAddress& addrFound = (*it).second;
+ int64 nUpdateInterval = 20 * 60;
+ if (addrFound.nTime < GetAdjustedTime() - nUpdateInterval)
+ {
+ // Periodically update most recently seen time
+ addrFound.nTime = GetAdjustedTime();
+ CAddrDB addrdb;
+ addrdb.WriteAddress(addrFound);
+ }
+ }
+ }
+}
+
+
+
+
+
+void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1)
+{
+ // If the dialog might get closed before the reply comes back,
+ // call this in the destructor so it doesn't get called after it's deleted.
+ CRITICAL_BLOCK(cs_vNodes)
+ {
+ BOOST_FOREACH(CNode* pnode, vNodes)
+ {
+ CRITICAL_BLOCK(pnode->cs_mapRequests)
+ {
+ for (map<uint256, CRequestTracker>::iterator mi = pnode->mapRequests.begin(); mi != pnode->mapRequests.end();)
+ {
+ CRequestTracker& tracker = (*mi).second;
+ if (tracker.fn == fn && tracker.param1 == param1)
+ pnode->mapRequests.erase(mi++);
+ else
+ mi++;
+ }
+ }
+ }
+ }
+}
+
+
+
+
+
+
+
+//
+// Subscription methods for the broadcast and subscription system.
+// Channel numbers are message numbers, i.e. MSG_TABLE and MSG_PRODUCT.
+//
+// The subscription system uses a meet-in-the-middle strategy.
+// With 100,000 nodes, if senders broadcast to 1000 random nodes and receivers
+// subscribe to 1000 random nodes, 99.995% (1 - 0.99^1000) of messages will get through.
+//
+
+bool AnySubscribed(unsigned int nChannel)
+{
+ if (pnodeLocalHost->IsSubscribed(nChannel))
+ return true;
+ CRITICAL_BLOCK(cs_vNodes)
+ BOOST_FOREACH(CNode* pnode, vNodes)
+ if (pnode->IsSubscribed(nChannel))
+ return true;
+ return false;
+}
+
+bool CNode::IsSubscribed(unsigned int nChannel)
+{
+ if (nChannel >= vfSubscribe.size())
+ return false;
+ return vfSubscribe[nChannel];
+}
+
+void CNode::Subscribe(unsigned int nChannel, unsigned int nHops)
+{
+ if (nChannel >= vfSubscribe.size())
+ return;
+
+ if (!AnySubscribed(nChannel))
+ {
+ // Relay subscribe
+ CRITICAL_BLOCK(cs_vNodes)
+ BOOST_FOREACH(CNode* pnode, vNodes)
+ if (pnode != this)
+ pnode->PushMessage("subscribe", nChannel, nHops);
+ }
+
+ vfSubscribe[nChannel] = true;
+}
+
+void CNode::CancelSubscribe(unsigned int nChannel)
+{
+ if (nChannel >= vfSubscribe.size())
+ return;
+
+ // Prevent from relaying cancel if wasn't subscribed
+ if (!vfSubscribe[nChannel])
+ return;
+ vfSubscribe[nChannel] = false;
+
+ if (!AnySubscribed(nChannel))
+ {
+ // Relay subscription cancel
+ CRITICAL_BLOCK(cs_vNodes)
+ BOOST_FOREACH(CNode* pnode, vNodes)
+ if (pnode != this)
+ pnode->PushMessage("sub-cancel", nChannel);
+ }
+}
+
+
+
+
+
+
+
+
+
+CNode* FindNode(unsigned int ip)
+{
+ CRITICAL_BLOCK(cs_vNodes)
+ {
+ BOOST_FOREACH(CNode* pnode, vNodes)
+ if (pnode->addr.ip == ip)
+ return (pnode);
+ }
+ return NULL;
+}
+
+CNode* FindNode(CAddress addr)
+{
+ CRITICAL_BLOCK(cs_vNodes)
+ {
+ BOOST_FOREACH(CNode* pnode, vNodes)
+ if (pnode->addr == addr)
+ return (pnode);
+ }
+ return NULL;
+}
+
+CNode* ConnectNode(CAddress addrConnect, int64 nTimeout)
+{
+ if (addrConnect.ip == addrLocalHost.ip)
+ return NULL;
+
+ // Look for an existing connection
+ CNode* pnode = FindNode(addrConnect.ip);
+ if (pnode)
+ {
+ if (nTimeout != 0)
+ pnode->AddRef(nTimeout);
+ else
+ pnode->AddRef();
+ return pnode;
+ }
+
+ /// debug print
+ printf("trying connection %s lastseen=%.1fhrs lasttry=%.1fhrs\n",
+ addrConnect.ToString().c_str(),
+ (double)(addrConnect.nTime - GetAdjustedTime())/3600.0,
+ (double)(addrConnect.nLastTry - GetAdjustedTime())/3600.0);
+
+ CRITICAL_BLOCK(cs_mapAddresses)
+ mapAddresses[addrConnect.GetKey()].nLastTry = GetAdjustedTime();
+
+ // Connect
+ SOCKET hSocket;
+ if (ConnectSocket(addrConnect, hSocket))
+ {
+ /// debug print
+ printf("connected %s\n", addrConnect.ToString().c_str());
+
+ // Set to nonblocking
+#ifdef __WXMSW__
+ u_long nOne = 1;
+ if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR)
+ printf("ConnectSocket() : ioctlsocket nonblocking setting failed, error %d\n", WSAGetLastError());
+#else
+ if (fcntl(hSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR)
+ printf("ConnectSocket() : fcntl nonblocking setting failed, error %d\n", errno);
+#endif
+
+ // Add node
+ CNode* pnode = new CNode(hSocket, addrConnect, false);
+ if (nTimeout != 0)
+ pnode->AddRef(nTimeout);
+ else
+ pnode->AddRef();
+ CRITICAL_BLOCK(cs_vNodes)
+ vNodes.push_back(pnode);
+
+ pnode->nTimeConnected = GetTime();
+ return pnode;
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+void CNode::CloseSocketDisconnect()
+{
+ fDisconnect = true;
+ if (hSocket != INVALID_SOCKET)
+ {
+ if (fDebug)
+ printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
+ printf("disconnecting node %s\n", addr.ToString().c_str());
+ closesocket(hSocket);
+ hSocket = INVALID_SOCKET;
+ }
+}
+
+void CNode::Cleanup()
+{
+ // All of a nodes broadcasts and subscriptions are automatically torn down
+ // when it goes down, so a node has to stay up to keep its broadcast going.
+
+ // Cancel subscriptions
+ for (unsigned int nChannel = 0; nChannel < vfSubscribe.size(); nChannel++)
+ if (vfSubscribe[nChannel])
+ CancelSubscribe(nChannel);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+void ThreadSocketHandler(void* parg)
+{
+ IMPLEMENT_RANDOMIZE_STACK(ThreadSocketHandler(parg));
+ try
+ {
+ vnThreadsRunning[0]++;
+ ThreadSocketHandler2(parg);
+ vnThreadsRunning[0]--;
+ }
+ catch (std::exception& e) {
+ vnThreadsRunning[0]--;
+ PrintException(&e, "ThreadSocketHandler()");
+ } catch (...) {
+ vnThreadsRunning[0]--;
+ throw; // support pthread_cancel()
+ }
+ printf("ThreadSocketHandler exiting\n");
+}
+
+void ThreadSocketHandler2(void* parg)
+{
+ printf("ThreadSocketHandler started\n");
+ list<CNode*> vNodesDisconnected;
+ int nPrevNodeCount = 0;
+
+ loop
+ {
+ //
+ // Disconnect nodes
+ //
+ CRITICAL_BLOCK(cs_vNodes)
+ {
+ // Disconnect unused nodes
+ vector<CNode*> vNodesCopy = vNodes;
+ BOOST_FOREACH(CNode* pnode, vNodesCopy)
+ {
+ if (pnode->fDisconnect ||
+ (pnode->GetRefCount() <= 0 && pnode->vRecv.empty() && pnode->vSend.empty()))
+ {
+ // remove from vNodes
+ vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end());
+
+ // close socket and cleanup
+ pnode->CloseSocketDisconnect();
+ pnode->Cleanup();
+
+ // hold in disconnected pool until all refs are released
+ pnode->nReleaseTime = max(pnode->nReleaseTime, GetTime() + 15 * 60);
+ if (pnode->fNetworkNode || pnode->fInbound)
+ pnode->Release();
+ vNodesDisconnected.push_back(pnode);
+ }
+ }
+
+ // Delete disconnected nodes
+ list<CNode*> vNodesDisconnectedCopy = vNodesDisconnected;
+ BOOST_FOREACH(CNode* pnode, vNodesDisconnectedCopy)
+ {
+ // wait until threads are done using it
+ if (pnode->GetRefCount() <= 0)
+ {
+ bool fDelete = false;
+ TRY_CRITICAL_BLOCK(pnode->cs_vSend)
+ TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
+ TRY_CRITICAL_BLOCK(pnode->cs_mapRequests)
+ TRY_CRITICAL_BLOCK(pnode->cs_inventory)
+ fDelete = true;
+ if (fDelete)
+ {
+ vNodesDisconnected.remove(pnode);
+ delete pnode;
+ }
+ }
+ }
+ }
+ if (vNodes.size() != nPrevNodeCount)
+ {
+ nPrevNodeCount = vNodes.size();
+ MainFrameRepaint();
+ }
+
+
+ //
+ // Find which sockets have data to receive
+ //
+ struct timeval timeout;
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 50000; // frequency to poll pnode->vSend
+
+ fd_set fdsetRecv;
+ fd_set fdsetSend;
+ fd_set fdsetError;
+ FD_ZERO(&fdsetRecv);
+ FD_ZERO(&fdsetSend);
+ FD_ZERO(&fdsetError);
+ SOCKET hSocketMax = 0;
+
+ if(hListenSocket != INVALID_SOCKET)
+ FD_SET(hListenSocket, &fdsetRecv);
+ hSocketMax = max(hSocketMax, hListenSocket);
+ CRITICAL_BLOCK(cs_vNodes)
+ {
+ BOOST_FOREACH(CNode* pnode, vNodes)
+ {
+ if (pnode->hSocket == INVALID_SOCKET || pnode->hSocket < 0)
+ continue;
+ FD_SET(pnode->hSocket, &fdsetRecv);
+ FD_SET(pnode->hSocket, &fdsetError);
+ hSocketMax = max(hSocketMax, pnode->hSocket);
+ TRY_CRITICAL_BLOCK(pnode->cs_vSend)
+ if (!pnode->vSend.empty())
+ FD_SET(pnode->hSocket, &fdsetSend);
+ }
+ }
+
+ vnThreadsRunning[0]--;
+ int nSelect = select(hSocketMax + 1, &fdsetRecv, &fdsetSend, &fdsetError, &timeout);
+ vnThreadsRunning[0]++;
+ if (fShutdown)
+ return;
+ if (nSelect == SOCKET_ERROR)
+ {
+ int nErr = WSAGetLastError();
+ printf("socket select error %d\n", nErr);
+ for (int i = 0; i <= hSocketMax; i++)
+ FD_SET(i, &fdsetRecv);
+ FD_ZERO(&fdsetSend);
+ FD_ZERO(&fdsetError);
+ Sleep(timeout.tv_usec/1000);
+ }
+
+
+ //
+ // Accept new connections
+ //
+ if (hListenSocket != INVALID_SOCKET && FD_ISSET(hListenSocket, &fdsetRecv))
+ {
+ struct sockaddr_in sockaddr;
+ socklen_t len = sizeof(sockaddr);
+ SOCKET hSocket = accept(hListenSocket, (struct sockaddr*)&sockaddr, &len);
+ CAddress addr(sockaddr);
+ int nInbound = 0;
+
+ CRITICAL_BLOCK(cs_vNodes)
+ BOOST_FOREACH(CNode* pnode, vNodes)
+ if (pnode->fInbound)
+ nInbound++;
+ if (hSocket == INVALID_SOCKET)
+ {
+ if (WSAGetLastError() != WSAEWOULDBLOCK)
+ printf("socket error accept failed: %d\n", WSAGetLastError());
+ }
+ else if (nInbound >= GetArg("-maxconnections", 125) - MAX_OUTBOUND_CONNECTIONS)
+ {
+ closesocket(hSocket);
+ }
+ else
+ {
+ printf("accepted connection %s\n", addr.ToString().c_str());
+ CNode* pnode = new CNode(hSocket, addr, true);
+ pnode->AddRef();
+ CRITICAL_BLOCK(cs_vNodes)
+ vNodes.push_back(pnode);
+ }
+ }
+
+
+ //
+ // Service each socket
+ //
+ vector<CNode*> vNodesCopy;
+ CRITICAL_BLOCK(cs_vNodes)
+ {
+ vNodesCopy = vNodes;
+ BOOST_FOREACH(CNode* pnode, vNodesCopy)
+ pnode->AddRef();
+ }
+ BOOST_FOREACH(CNode* pnode, vNodesCopy)
+ {
+ if (fShutdown)
+ return;
+
+ //
+ // Receive
+ //
+ if (pnode->hSocket == INVALID_SOCKET)
+ continue;
+ if (FD_ISSET(pnode->hSocket, &fdsetRecv) || FD_ISSET(pnode->hSocket, &fdsetError))
+ {
+ TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
+ {
+ CDataStream& vRecv = pnode->vRecv;
+ unsigned int nPos = vRecv.size();
+
+ if (nPos > 1000*GetArg("-maxreceivebuffer", 10*1000)) {
+ if (!pnode->fDisconnect)
+ printf("socket recv flood control disconnect (%d bytes)\n", vRecv.size());
+ pnode->CloseSocketDisconnect();
+ }
+ else {
+ // typical socket buffer is 8K-64K
+ char pchBuf[0x10000];
+ int nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT);
+ if (nBytes > 0)
+ {
+ vRecv.resize(nPos + nBytes);
+ memcpy(&vRecv[nPos], pchBuf, nBytes);
+ pnode->nLastRecv = GetTime();
+ }
+ else if (nBytes == 0)
+ {
+ // socket closed gracefully
+ if (!pnode->fDisconnect)
+ printf("socket closed\n");
+ pnode->CloseSocketDisconnect();
+ }
+ else if (nBytes < 0)
+ {
+ // error
+ int nErr = WSAGetLastError();
+ if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
+ {
+ if (!pnode->fDisconnect)
+ printf("socket recv error %d\n", nErr);
+ pnode->CloseSocketDisconnect();
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // Send
+ //
+ if (pnode->hSocket == INVALID_SOCKET)
+ continue;
+ if (FD_ISSET(pnode->hSocket, &fdsetSend))
+ {
+ TRY_CRITICAL_BLOCK(pnode->cs_vSend)
+ {
+ CDataStream& vSend = pnode->vSend;
+ if (!vSend.empty())
+ {
+ int nBytes = send(pnode->hSocket, &vSend[0], vSend.size(), MSG_NOSIGNAL | MSG_DONTWAIT);
+ if (nBytes > 0)
+ {
+ vSend.erase(vSend.begin(), vSend.begin() + nBytes);
+ pnode->nLastSend = GetTime();
+ }
+ else if (nBytes < 0)
+ {
+ // error
+ int nErr = WSAGetLastError();
+ if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
+ {
+ printf("socket send error %d\n", nErr);
+ pnode->CloseSocketDisconnect();
+ }
+ }
+ if (vSend.size() > 1000*GetArg("-maxsendbuffer", 10*1000)) {
+ if (!pnode->fDisconnect)
+ printf("socket send flood control disconnect (%d bytes)\n", vSend.size());
+ pnode->CloseSocketDisconnect();
+ }
+ }
+ }
+ }
+
+ //
+ // Inactivity checking
+ //
+ if (pnode->vSend.empty())
+ pnode->nLastSendEmpty = GetTime();
+ if (GetTime() - pnode->nTimeConnected > 60)
+ {
+ if (pnode->nLastRecv == 0 || pnode->nLastSend == 0)
+ {
+ printf("socket no message in first 60 seconds, %d %d\n", pnode->nLastRecv != 0, pnode->nLastSend != 0);
+ pnode->fDisconnect = true;
+ }
+ else if (GetTime() - pnode->nLastSend > 90*60 && GetTime() - pnode->nLastSendEmpty > 90*60)
+ {
+ printf("socket not sending\n");
+ pnode->fDisconnect = true;
+ }
+ else if (GetTime() - pnode->nLastRecv > 90*60)
+ {
+ printf("socket inactivity timeout\n");
+ pnode->fDisconnect = true;
+ }
+ }
+ }
+ CRITICAL_BLOCK(cs_vNodes)
+ {
+ BOOST_FOREACH(CNode* pnode, vNodesCopy)
+ pnode->Release();
+ }
+
+ Sleep(10);
+ }
+}
+
+
+
+
+
+
+
+
+
+#ifdef USE_UPNP
+void ThreadMapPort(void* parg)
+{
+ IMPLEMENT_RANDOMIZE_STACK(ThreadMapPort(parg));
+ try
+ {
+ vnThreadsRunning[5]++;
+ ThreadMapPort2(parg);
+ vnThreadsRunning[5]--;
+ }
+ catch (std::exception& e) {
+ vnThreadsRunning[5]--;
+ PrintException(&e, "ThreadMapPort()");
+ } catch (...) {
+ vnThreadsRunning[5]--;
+ PrintException(NULL, "ThreadMapPort()");
+ }
+ printf("ThreadMapPort exiting\n");
+}
+
+void ThreadMapPort2(void* parg)
+{
+ printf("ThreadMapPort started\n");
+
+ char port[6];
+ sprintf(port, "%d", GetDefaultPort());
+
+ const char * rootdescurl = 0;
+ const char * multicastif = 0;
+ const char * minissdpdpath = 0;
+ struct UPNPDev * devlist = 0;
+ char lanaddr[64];
+
+ devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0);
+
+ struct UPNPUrls urls;
+ struct IGDdatas data;
+ int r;
+
+ r = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr));
+ if (r == 1)
+ {
+ char intClient[16];
+ char intPort[6];
+
+#ifndef __WXMSW__
+ r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype,
+ port, port, lanaddr, 0, "TCP", 0);
+#else
+ r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype,
+ port, port, lanaddr, 0, "TCP", 0, "0");
+#endif
+ if(r!=UPNPCOMMAND_SUCCESS)
+ printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n",
+ port, port, lanaddr, r, strupnperror(r));
+ else
+ printf("UPnP Port Mapping successful.\n");
+ loop {
+ if (fShutdown || !fUseUPnP)
+ {
+ r = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, port, "TCP", 0);
+ printf("UPNP_DeletePortMapping() returned : %d\n", r);
+ freeUPNPDevlist(devlist); devlist = 0;
+ FreeUPNPUrls(&urls);
+ return;
+ }
+ Sleep(2000);
+ }
+ } else {
+ printf("No valid UPnP IGDs found\n");
+ freeUPNPDevlist(devlist); devlist = 0;
+ if (r != 0)
+ FreeUPNPUrls(&urls);
+ loop {
+ if (fShutdown || !fUseUPnP)
+ return;
+ Sleep(2000);
+ }
+ }
+}
+
+void MapPort(bool fMapPort)
+{
+ if (fUseUPnP != fMapPort)
+ {
+ fUseUPnP = fMapPort;
+ CWalletDB().WriteSetting("fUseUPnP", fUseUPnP);
+ }
+ if (fUseUPnP && vnThreadsRunning[5] < 1)
+ {
+ if (!CreateThread(ThreadMapPort, NULL))
+ printf("Error: ThreadMapPort(ThreadMapPort) failed\n");
+ }
+}
+#endif
+
+
+
+
+
+
+
+
+
+
+static const char *strDNSSeed[] = {
+ "bitseed.xf2.org",
+ "bitseed.bitcoin.org.uk",
+};
+
+void DNSAddressSeed()
+{
+ int found = 0;
+
+ printf("Loading addresses from DNS seeds (could take a while)\n");
+
+ for (int seed_idx = 0; seed_idx < ARRAYLEN(strDNSSeed); seed_idx++) {
+ vector<CAddress> vaddr;
+ if (Lookup(strDNSSeed[seed_idx], vaddr, NODE_NETWORK, true))
+ {
+ BOOST_FOREACH (CAddress& addr, vaddr)
+ {
+ if (addr.GetByte(3) != 127)
+ {
+ addr.nTime = 0;
+ AddAddress(addr);
+ found++;
+ }
+ }
+ }
+ }
+
+ printf("%d addresses found from DNS seeds\n", found);
+}
+
+
+
+unsigned int pnSeed[] =
+{
+ 0x1ddb1032, 0x6242ce40, 0x52d6a445, 0x2dd7a445, 0x8a53cd47, 0x73263750, 0xda23c257, 0xecd4ed57,
+ 0x0a40ec59, 0x75dce160, 0x7df76791, 0x89370bad, 0xa4f214ad, 0x767700ae, 0x638b0418, 0x868a1018,
+ 0xcd9f332e, 0x0129653e, 0xcc92dc3e, 0x96671640, 0x56487e40, 0x5b66f440, 0xb1d01f41, 0xf1dc6041,
+ 0xc1d12b42, 0x86ba1243, 0x6be4df43, 0x6d4cef43, 0xd18e0644, 0x1ab0b344, 0x6584a345, 0xe7c1a445,
+ 0x58cea445, 0xc5daa445, 0x21dda445, 0x3d3b5346, 0x13e55347, 0x1080d24a, 0x8e611e4b, 0x81518e4b,
+ 0x6c839e4b, 0xe2ad0a4c, 0xfbbc0a4c, 0x7f5b6e4c, 0x7244224e, 0x1300554e, 0x20690652, 0x5a48b652,
+ 0x75c5c752, 0x4335cc54, 0x340fd154, 0x87c07455, 0x087b2b56, 0x8a133a57, 0xac23c257, 0x70374959,
+ 0xfb63d45b, 0xb9a1685c, 0x180d765c, 0x674f645d, 0x04d3495e, 0x1de44b5e, 0x4ee8a362, 0x0ded1b63,
+ 0xc1b04b6d, 0x8d921581, 0x97b7ea82, 0x1cf83a8e, 0x91490bad, 0x09dc75ae, 0x9a6d79ae, 0xa26d79ae,
+ 0x0fd08fae, 0x0f3e3fb2, 0x4f944fb2, 0xcca448b8, 0x3ecd6ab8, 0xa9d5a5bc, 0x8d0119c1, 0x045997d5,
+ 0xca019dd9, 0x0d526c4d, 0xabf1ba44, 0x66b1ab55, 0x1165f462, 0x3ed7cbad, 0xa38fae6e, 0x3bd2cbad,
+ 0xd36f0547, 0x20df7840, 0x7a337742, 0x549f8e4b, 0x9062365c, 0xd399f562, 0x2b5274a1, 0x8edfa153,
+ 0x3bffb347, 0x7074bf58, 0xb74fcbad, 0x5b5a795b, 0x02fa29ce, 0x5a6738d4, 0xe8a1d23e, 0xef98c445,
+ 0x4b0f494c, 0xa2bc1e56, 0x7694ad63, 0xa4a800c3, 0x05fda6cd, 0x9f22175e, 0x364a795b, 0x536285d5,
+ 0xac44c9d4, 0x0b06254d, 0x150c2fd4, 0x32a50dcc, 0xfd79ce48, 0xf15cfa53, 0x66c01e60, 0x6bc26661,
+ 0xc03b47ae, 0x4dda1b81, 0x3285a4c1, 0x883ca96d, 0x35d60a4c, 0xdae09744, 0x2e314d61, 0x84e247cf,
+ 0x6c814552, 0x3a1cc658, 0x98d8f382, 0xe584cb5b, 0x15e86057, 0x7b01504e, 0xd852dd48, 0x56382f56,
+ 0x0a5df454, 0xa0d18d18, 0x2e89b148, 0xa79c114c, 0xcbdcd054, 0x5523bc43, 0xa9832640, 0x8a066144,
+ 0x3894c3bc, 0xab76bf58, 0x6a018ac1, 0xfebf4f43, 0x2f26c658, 0x31102f4e, 0x85e929d5, 0x2a1c175e,
+ 0xfc6c2cd1, 0x27b04b6d, 0xdf024650, 0x161748b8, 0x28be6580, 0x57be6580, 0x1cee677a, 0xaa6bb742,
+ 0x9a53964b, 0x0a5a2d4d, 0x2434c658, 0x9a494f57, 0x1ebb0e48, 0xf610b85d, 0x077ecf44, 0x085128bc,
+ 0x5ba17a18, 0x27ca1b42, 0xf8a00b56, 0xfcd4c257, 0xcf2fc15e, 0xd897e052, 0x4cada04f, 0x2f35f6d5,
+ 0x382ce8c9, 0xe523984b, 0x3f946846, 0x60c8be43, 0x41da6257, 0xde0be142, 0xae8a544b, 0xeff0c254,
+ 0x1e0f795b, 0xaeb28890, 0xca16acd9, 0x1e47ddd8, 0x8c8c4829, 0xd27dc747, 0xd53b1663, 0x4096b163,
+ 0x9c8dd958, 0xcb12f860, 0x9e79305c, 0x40c1a445, 0x4a90c2bc, 0x2c3a464d, 0x2727f23c, 0x30b04b6d,
+ 0x59024cb8, 0xa091e6ad, 0x31b04b6d, 0xc29d46a6, 0x63934fb2, 0xd9224dbe, 0x9f5910d8, 0x7f530a6b,
+ 0x752e9c95, 0x65453548, 0xa484be46, 0xce5a1b59, 0x710e0718, 0x46a13d18, 0xdaaf5318, 0xc4a8ff53,
+ 0x87abaa52, 0xb764cf51, 0xb2025d4a, 0x6d351e41, 0xc035c33e, 0xa432c162, 0x61ef34ae, 0xd16fddbc,
+ 0x0870e8c1, 0x3070e8c1, 0x9c71e8c1, 0xa4992363, 0x85a1f663, 0x4184e559, 0x18d96ed8, 0x17b8dbd5,
+ 0x60e7cd18, 0xe5ee104c, 0xab17ac62, 0x1e786e1b, 0x5d23b762, 0xf2388fae, 0x88270360, 0x9e5b3d80,
+ 0x7da518b2, 0xb5613b45, 0x1ad41f3e, 0xd550854a, 0x8617e9a9, 0x925b229c, 0xf2e92542, 0x47af0544,
+ 0x73b5a843, 0xb9b7a0ad, 0x03a748d0, 0x0a6ff862, 0x6694df62, 0x3bfac948, 0x8e098f4f, 0x746916c3,
+ 0x02f38e4f, 0x40bb1243, 0x6a54d162, 0x6008414b, 0xa513794c, 0x514aa343, 0x63781747, 0xdbb6795b,
+ 0xed065058, 0x42d24b46, 0x1518794c, 0x9b271681, 0x73e4ffad, 0x0654784f, 0x438dc945, 0x641846a6,
+ 0x2d1b0944, 0x94b59148, 0x8d369558, 0xa5a97662, 0x8b705b42, 0xce9204ae, 0x8d584450, 0x2df61555,
+ 0xeebff943, 0x2e75fb4d, 0x3ef8fc57, 0x9921135e, 0x8e31042e, 0xb5afad43, 0x89ecedd1, 0x9cfcc047,
+ 0x8fcd0f4c, 0xbe49f5ad, 0x146a8d45, 0x98669ab8, 0x98d9175e, 0xd1a8e46d, 0x839a3ab8, 0x40a0016c,
+ 0x6d27c257, 0x977fffad, 0x7baa5d5d, 0x1213be43, 0xb167e5a9, 0x640fe8ca, 0xbc9ea655, 0x0f820a4c,
+ 0x0f097059, 0x69ac957c, 0x366d8453, 0xb1ba2844, 0x8857f081, 0x70b5be63, 0xc545454b, 0xaf36ded1,
+ 0xb5a4b052, 0x21f062d1, 0x72ab89b2, 0x74a45318, 0x8312e6bc, 0xb916965f, 0x8aa7c858, 0xfe7effad,
+};
+
+
+
+void ThreadOpenConnections(void* parg)
+{
+ IMPLEMENT_RANDOMIZE_STACK(ThreadOpenConnections(parg));
+ try
+ {
+ vnThreadsRunning[1]++;
+ ThreadOpenConnections2(parg);
+ vnThreadsRunning[1]--;
+ }
+ catch (std::exception& e) {
+ vnThreadsRunning[1]--;
+ PrintException(&e, "ThreadOpenConnections()");
+ } catch (...) {
+ vnThreadsRunning[1]--;
+ PrintException(NULL, "ThreadOpenConnections()");
+ }
+ printf("ThreadOpenConnections exiting\n");
+}
+
+void ThreadOpenConnections2(void* parg)
+{
+ printf("ThreadOpenConnections started\n");
+
+ // Connect to specific addresses
+ if (mapArgs.count("-connect"))
+ {
+ for (int64 nLoop = 0;; nLoop++)
+ {
+ BOOST_FOREACH(string strAddr, mapMultiArgs["-connect"])
+ {
+ CAddress addr(strAddr, fAllowDNS);
+ if (addr.IsValid())
+ OpenNetworkConnection(addr);
+ for (int i = 0; i < 10 && i < nLoop; i++)
+ {
+ Sleep(500);
+ if (fShutdown)
+ return;
+ }
+ }
+ }
+ }
+
+ // Connect to manually added nodes first
+ if (mapArgs.count("-addnode"))
+ {
+ BOOST_FOREACH(string strAddr, mapMultiArgs["-addnode"])
+ {
+ CAddress addr(strAddr, fAllowDNS);
+ if (addr.IsValid())
+ {
+ OpenNetworkConnection(addr);
+ Sleep(500);
+ if (fShutdown)
+ return;
+ }
+ }
+ }
+
+ // Initiate network connections
+ int64 nStart = GetTime();
+ loop
+ {
+ // Limit outbound connections
+ vnThreadsRunning[1]--;
+ Sleep(500);
+ loop
+ {
+ int nOutbound = 0;
+ CRITICAL_BLOCK(cs_vNodes)
+ BOOST_FOREACH(CNode* pnode, vNodes)
+ if (!pnode->fInbound)
+ nOutbound++;
+ int nMaxOutboundConnections = MAX_OUTBOUND_CONNECTIONS;
+ nMaxOutboundConnections = min(nMaxOutboundConnections, (int)GetArg("-maxconnections", 125));
+ if (nOutbound < nMaxOutboundConnections)
+ break;
+ Sleep(2000);
+ if (fShutdown)
+ return;
+ }
+ vnThreadsRunning[1]++;
+ if (fShutdown)
+ return;
+
+ CRITICAL_BLOCK(cs_mapAddresses)
+ {
+ // Add seed nodes if IRC isn't working
+ static bool fSeedUsed;
+ bool fTOR = (fUseProxy && addrProxy.port == htons(9050));
+ if (mapAddresses.empty() && (GetTime() - nStart > 60 || fTOR) && !fTestNet)
+ {
+ for (int i = 0; i < ARRAYLEN(pnSeed); i++)
+ {
+ // It'll only connect to one or two seed nodes because once it connects,
+ // it'll get a pile of addresses with newer timestamps.
+ CAddress addr;
+ addr.ip = pnSeed[i];
+ addr.nTime = 0;
+ AddAddress(addr);
+ }
+ fSeedUsed = true;
+ }
+
+ if (fSeedUsed && mapAddresses.size() > ARRAYLEN(pnSeed) + 100)
+ {
+ // Disconnect seed nodes
+ set<unsigned int> setSeed(pnSeed, pnSeed + ARRAYLEN(pnSeed));
+ static int64 nSeedDisconnected;
+ if (nSeedDisconnected == 0)
+ {
+ nSeedDisconnected = GetTime();
+ CRITICAL_BLOCK(cs_vNodes)
+ BOOST_FOREACH(CNode* pnode, vNodes)
+ if (setSeed.count(pnode->addr.ip))
+ pnode->fDisconnect = true;
+ }
+
+ // Keep setting timestamps to 0 so they won't reconnect
+ if (GetTime() - nSeedDisconnected < 60 * 60)
+ {
+ BOOST_FOREACH(PAIRTYPE(const vector<unsigned char>, CAddress)& item, mapAddresses)
+ {
+ if (setSeed.count(item.second.ip) && item.second.nTime != 0)
+ {
+ item.second.nTime = 0;
+ CAddrDB().WriteAddress(item.second);
+ }
+ }
+ }
+ }
+ }
+
+
+ //
+ // Choose an address to connect to based on most recently seen
+ //
+ CAddress addrConnect;
+ int64 nBest = INT64_MIN;
+
+ // Only connect to one address per a.b.?.? range.
+ // Do this here so we don't have to critsect vNodes inside mapAddresses critsect.
+ set<unsigned int> setConnected;
+ CRITICAL_BLOCK(cs_vNodes)
+ BOOST_FOREACH(CNode* pnode, vNodes)
+ setConnected.insert(pnode->addr.ip & 0x0000ffff);
+
+ CRITICAL_BLOCK(cs_mapAddresses)
+ {
+ BOOST_FOREACH(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses)
+ {
+ const CAddress& addr = item.second;
+ if (!addr.IsIPv4() || !addr.IsValid() || setConnected.count(addr.ip & 0x0000ffff))
+ continue;
+ int64 nSinceLastSeen = GetAdjustedTime() - addr.nTime;
+ int64 nSinceLastTry = GetAdjustedTime() - addr.nLastTry;
+
+ // Randomize the order in a deterministic way, putting the standard port first
+ int64 nRandomizer = (uint64)(nStart * 4951 + addr.nLastTry * 9567851 + addr.ip * 7789) % (2 * 60 * 60);
+ if (addr.port != htons(GetDefaultPort()))
+ nRandomizer += 2 * 60 * 60;
+
+ // Last seen Base retry frequency
+ // <1 hour 10 min
+ // 1 hour 1 hour
+ // 4 hours 2 hours
+ // 24 hours 5 hours
+ // 48 hours 7 hours
+ // 7 days 13 hours
+ // 30 days 27 hours
+ // 90 days 46 hours
+ // 365 days 93 hours
+ int64 nDelay = (int64)(3600.0 * sqrt(fabs((double)nSinceLastSeen) / 3600.0) + nRandomizer);
+
+ // Fast reconnect for one hour after last seen
+ if (nSinceLastSeen < 60 * 60)
+ nDelay = 10 * 60;
+
+ // Limit retry frequency
+ if (nSinceLastTry < nDelay)
+ continue;
+
+ // If we have IRC, we'll be notified when they first come online,
+ // and again every 24 hours by the refresh broadcast.
+ if (nGotIRCAddresses > 0 && vNodes.size() >= 2 && nSinceLastSeen > 24 * 60 * 60)
+ continue;
+
+ // Only try the old stuff if we don't have enough connections
+ if (vNodes.size() >= 8 && nSinceLastSeen > 24 * 60 * 60)
+ continue;
+
+ // If multiple addresses are ready, prioritize by time since
+ // last seen and time since last tried.
+ int64 nScore = min(nSinceLastTry, (int64)24 * 60 * 60) - nSinceLastSeen - nRandomizer;
+ if (nScore > nBest)
+ {
+ nBest = nScore;
+ addrConnect = addr;
+ }
+ }
+ }
+
+ if (addrConnect.IsValid())
+ OpenNetworkConnection(addrConnect);
+ }
+}
+
+bool OpenNetworkConnection(const CAddress& addrConnect)
+{
+ //
+ // Initiate outbound network connection
+ //
+ if (fShutdown)
+ return false;
+ if (addrConnect.ip == addrLocalHost.ip || !addrConnect.IsIPv4() || FindNode(addrConnect.ip))
+ return false;
+
+ vnThreadsRunning[1]--;
+ CNode* pnode = ConnectNode(addrConnect);
+ vnThreadsRunning[1]++;
+ if (fShutdown)
+ return false;
+ if (!pnode)
+ return false;
+ pnode->fNetworkNode = true;
+
+ return true;
+}
+
+
+
+
+
+
+
+
+void ThreadMessageHandler(void* parg)
+{
+ IMPLEMENT_RANDOMIZE_STACK(ThreadMessageHandler(parg));
+ try
+ {
+ vnThreadsRunning[2]++;
+ ThreadMessageHandler2(parg);
+ vnThreadsRunning[2]--;
+ }
+ catch (std::exception& e) {
+ vnThreadsRunning[2]--;
+ PrintException(&e, "ThreadMessageHandler()");
+ } catch (...) {
+ vnThreadsRunning[2]--;
+ PrintException(NULL, "ThreadMessageHandler()");
+ }
+ printf("ThreadMessageHandler exiting\n");
+}
+
+void ThreadMessageHandler2(void* parg)
+{
+ printf("ThreadMessageHandler started\n");
+ SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL);
+ while (!fShutdown)
+ {
+ vector<CNode*> vNodesCopy;
+ CRITICAL_BLOCK(cs_vNodes)
+ {
+ vNodesCopy = vNodes;
+ BOOST_FOREACH(CNode* pnode, vNodesCopy)
+ pnode->AddRef();
+ }
+
+ // Poll the connected nodes for messages
+ CNode* pnodeTrickle = NULL;
+ if (!vNodesCopy.empty())
+ pnodeTrickle = vNodesCopy[GetRand(vNodesCopy.size())];
+ BOOST_FOREACH(CNode* pnode, vNodesCopy)
+ {
+ // Receive messages
+ TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
+ ProcessMessages(pnode);
+ if (fShutdown)
+ return;
+
+ // Send messages
+ TRY_CRITICAL_BLOCK(pnode->cs_vSend)
+ SendMessages(pnode, pnode == pnodeTrickle);
+ if (fShutdown)
+ return;
+ }
+
+ CRITICAL_BLOCK(cs_vNodes)
+ {
+ BOOST_FOREACH(CNode* pnode, vNodesCopy)
+ pnode->Release();
+ }
+
+ // Wait and allow messages to bunch up.
+ // Reduce vnThreadsRunning so StopNode has permission to exit while
+ // we're sleeping, but we must always check fShutdown after doing this.
+ vnThreadsRunning[2]--;
+ Sleep(100);
+ if (fRequestShutdown)
+ Shutdown(NULL);
+ vnThreadsRunning[2]++;
+ if (fShutdown)
+ return;
+ }
+}
+
+
+
+
+
+
+
+
+
+bool BindListenPort(string& strError)
+{
+ strError = "";
+ int nOne = 1;
+ addrLocalHost.port = htons(GetDefaultPort());
+
+#ifdef __WXMSW__
+ // Initialize Windows Sockets
+ WSADATA wsadata;
+ int ret = WSAStartup(MAKEWORD(2,2), &wsadata);
+ if (ret != NO_ERROR)
+ {
+ strError = strprintf("Error: TCP/IP socket library failed to start (WSAStartup returned error %d)", ret);
+ printf("%s\n", strError.c_str());
+ return false;
+ }
+#endif
+
+ // Create socket for listening for incoming connections
+ hListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (hListenSocket == INVALID_SOCKET)
+ {
+ strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %d)", WSAGetLastError());
+ printf("%s\n", strError.c_str());
+ return false;
+ }
+
+#ifdef BSD
+ // Different way of disabling SIGPIPE on BSD
+ setsockopt(hListenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&nOne, sizeof(int));
+#endif
+
+#ifndef __WXMSW__
+ // Allow binding if the port is still in TIME_WAIT state after
+ // the program was closed and restarted. Not an issue on windows.
+ setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int));
+#endif
+
+#ifdef __WXMSW__
+ // Set to nonblocking, incoming connections will also inherit this
+ if (ioctlsocket(hListenSocket, FIONBIO, (u_long*)&nOne) == SOCKET_ERROR)
+#else
+ if (fcntl(hListenSocket, F_SETFL, O_NONBLOCK) == SOCKET_ERROR)
+#endif
+ {
+ strError = strprintf("Error: Couldn't set properties on socket for incoming connections (error %d)", WSAGetLastError());
+ printf("%s\n", strError.c_str());
+ return false;
+ }
+
+ // The sockaddr_in structure specifies the address family,
+ // IP address, and port for the socket that is being bound
+ struct sockaddr_in sockaddr;
+ memset(&sockaddr, 0, sizeof(sockaddr));
+ sockaddr.sin_family = AF_INET;
+ sockaddr.sin_addr.s_addr = INADDR_ANY; // bind to all IPs on this computer
+ sockaddr.sin_port = htons(GetDefaultPort());
+ if (::bind(hListenSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR)
+ {
+ int nErr = WSAGetLastError();
+ if (nErr == WSAEADDRINUSE)
+ strError = strprintf(_("Unable to bind to port %d on this computer. Bitcoin is probably already running."), ntohs(sockaddr.sin_port));
+ else
+ strError = strprintf("Error: Unable to bind to port %d on this computer (bind returned error %d)", ntohs(sockaddr.sin_port), nErr);
+ printf("%s\n", strError.c_str());
+ return false;
+ }
+ printf("Bound to port %d\n", ntohs(sockaddr.sin_port));
+
+ // Listen for incoming connections
+ if (listen(hListenSocket, SOMAXCONN) == SOCKET_ERROR)
+ {
+ strError = strprintf("Error: Listening for incoming connections failed (listen returned error %d)", WSAGetLastError());
+ printf("%s\n", strError.c_str());
+ return false;
+ }
+
+ return true;
+}
+
+void StartNode(void* parg)
+{
+ if (pnodeLocalHost == NULL)
+ pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress("127.0.0.1", 0, false, nLocalServices));
+
+#ifdef __WXMSW__
+ // Get local host ip
+ char pszHostName[1000] = "";
+ if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR)
+ {
+ vector<CAddress> vaddr;
+ if (NameLookup(pszHostName, vaddr, nLocalServices))
+ BOOST_FOREACH (const CAddress &addr, vaddr)
+ if (addr.GetByte(3) != 127)
+ {
+ addrLocalHost = addr;
+ break;
+ }
+ }
+#else
+ // Get local host ip
+ struct ifaddrs* myaddrs;
+ if (getifaddrs(&myaddrs) == 0)
+ {
+ for (struct ifaddrs* ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next)
+ {
+ if (ifa->ifa_addr == NULL) continue;
+ if ((ifa->ifa_flags & IFF_UP) == 0) continue;
+ if (strcmp(ifa->ifa_name, "lo") == 0) continue;
+ if (strcmp(ifa->ifa_name, "lo0") == 0) continue;
+ char pszIP[100];
+ if (ifa->ifa_addr->sa_family == AF_INET)
+ {
+ struct sockaddr_in* s4 = (struct sockaddr_in*)(ifa->ifa_addr);
+ if (inet_ntop(ifa->ifa_addr->sa_family, (void*)&(s4->sin_addr), pszIP, sizeof(pszIP)) != NULL)
+ printf("ipv4 %s: %s\n", ifa->ifa_name, pszIP);
+
+ // Take the first IP that isn't loopback 127.x.x.x
+ CAddress addr(*(unsigned int*)&s4->sin_addr, 0, nLocalServices);
+ if (addr.IsValid() && addr.GetByte(3) != 127)
+ {
+ addrLocalHost = addr;
+ break;
+ }
+ }
+ else if (ifa->ifa_addr->sa_family == AF_INET6)
+ {
+ struct sockaddr_in6* s6 = (struct sockaddr_in6*)(ifa->ifa_addr);
+ if (inet_ntop(ifa->ifa_addr->sa_family, (void*)&(s6->sin6_addr), pszIP, sizeof(pszIP)) != NULL)
+ printf("ipv6 %s: %s\n", ifa->ifa_name, pszIP);
+ }
+ }
+ freeifaddrs(myaddrs);
+ }
+#endif
+ printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str());
+
+ if (fUseProxy || mapArgs.count("-connect") || fNoListen)
+ {
+ // Proxies can't take incoming connections
+ addrLocalHost.ip = CAddress("0.0.0.0").ip;
+ printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str());
+ }
+ else
+ {
+ CreateThread(ThreadGetMyExternalIP, NULL);
+ }
+
+ //
+ // Start threads
+ //
+
+ // Map ports with UPnP
+ if (fHaveUPnP)
+ MapPort(fUseUPnP);
+
+ // Get addresses from IRC and advertise ours
+ if (!CreateThread(ThreadIRCSeed, NULL))
+ printf("Error: CreateThread(ThreadIRCSeed) failed\n");
+
+ // Send and receive from sockets, accept connections
+ pthread_t hThreadSocketHandler = CreateThread(ThreadSocketHandler, NULL, true);
+
+ // Initiate outbound connections
+ if (!CreateThread(ThreadOpenConnections, NULL))
+ printf("Error: CreateThread(ThreadOpenConnections) failed\n");
+
+ // Process messages
+ if (!CreateThread(ThreadMessageHandler, NULL))
+ printf("Error: CreateThread(ThreadMessageHandler) failed\n");
+
+ // Generate coins in the background
+ GenerateBitcoins(fGenerateBitcoins);
+}
+
+bool StopNode()
+{
+ printf("StopNode()\n");
+ fShutdown = true;
+ nTransactionsUpdated++;
+ int64 nStart = GetTime();
+ while (vnThreadsRunning[0] > 0 || vnThreadsRunning[2] > 0 || vnThreadsRunning[3] > 0 || vnThreadsRunning[4] > 0
+#ifdef USE_UPNP
+ || vnThreadsRunning[5] > 0
+#endif
+ )
+ {
+ if (GetTime() - nStart > 20)
+ break;
+ Sleep(20);
+ }
+ if (vnThreadsRunning[0] > 0) printf("ThreadSocketHandler still running\n");
+ if (vnThreadsRunning[1] > 0) printf("ThreadOpenConnections still running\n");
+ if (vnThreadsRunning[2] > 0) printf("ThreadMessageHandler still running\n");
+ if (vnThreadsRunning[3] > 0) printf("ThreadBitcoinMiner still running\n");
+ if (vnThreadsRunning[4] > 0) printf("ThreadRPCServer still running\n");
+ if (fHaveUPnP && vnThreadsRunning[5] > 0) printf("ThreadMapPort still running\n");
+ while (vnThreadsRunning[2] > 0 || vnThreadsRunning[4] > 0)
+ Sleep(20);
+ Sleep(50);
+
+ return true;
+}
+
+class CNetCleanup
+{
+public:
+ CNetCleanup()
+ {
+ }
+ ~CNetCleanup()
+ {
+ // Close sockets
+ BOOST_FOREACH(CNode* pnode, vNodes)
+ if (pnode->hSocket != INVALID_SOCKET)
+ closesocket(pnode->hSocket);
+ if (hListenSocket != INVALID_SOCKET)
+ if (closesocket(hListenSocket) == SOCKET_ERROR)
+ printf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError());
+
+#ifdef __WXMSW__
+ // Shutdown Windows Sockets
+ WSACleanup();
+#endif
+ }
+}
+instance_of_cnetcleanup;
diff --git a/core/src/rpc.cpp b/core/src/rpc.cpp
new file mode 100644
index 0000000000..9efcbbb15a
--- /dev/null
+++ b/core/src/rpc.cpp
@@ -0,0 +1,2195 @@
+// Copyright (c) 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.
+
+#include "headers.h"
+#include "cryptopp/sha.h"
+#undef printf
+#include <boost/asio.hpp>
+#include <boost/iostreams/concepts.hpp>
+#include <boost/iostreams/stream.hpp>
+#ifdef USE_SSL
+#include <boost/asio/ssl.hpp>
+typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
+#endif
+#include "json/json_spirit_reader_template.h"
+#include "json/json_spirit_writer_template.h"
+#include "json/json_spirit_utils.h"
+#define printf OutputDebugStringF
+// MinGW 3.4.5 gets "fatal error: had to relocate PCH" if the json headers are
+// precompiled in headers.h. The problem might be when the pch file goes over
+// a certain size around 145MB. If we need access to json_spirit outside this
+// file, we could use the compiled json_spirit option.
+
+using namespace std;
+using namespace boost;
+using namespace boost::asio;
+using namespace json_spirit;
+
+void ThreadRPCServer2(void* parg);
+typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
+extern map<string, rpcfn_type> mapCallTable;
+
+
+Object JSONRPCError(int code, const string& message)
+{
+ Object error;
+ error.push_back(Pair("code", code));
+ error.push_back(Pair("message", message));
+ return error;
+}
+
+
+void PrintConsole(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("%s", buffer);
+#if defined(__WXMSW__) && defined(GUI)
+ MyMessageBox(buffer, "Bitcoin", wxOK | wxICON_EXCLAMATION);
+#else
+ fprintf(stdout, "%s", buffer);
+#endif
+}
+
+
+int64 AmountFromValue(const Value& value)
+{
+ double dAmount = value.get_real();
+ if (dAmount <= 0.0 || dAmount > 21000000.0)
+ throw JSONRPCError(-3, "Invalid amount");
+ int64 nAmount = roundint64(dAmount * COIN);
+ if (!MoneyRange(nAmount))
+ throw JSONRPCError(-3, "Invalid amount");
+ return nAmount;
+}
+
+Value ValueFromAmount(int64 amount)
+{
+ return (double)amount / (double)COIN;
+}
+
+void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
+{
+ entry.push_back(Pair("confirmations", wtx.GetDepthInMainChain()));
+ entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
+ entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
+ BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
+ entry.push_back(Pair(item.first, item.second));
+}
+
+string AccountFromValue(const Value& value)
+{
+ string strAccount = value.get_str();
+ if (strAccount == "*")
+ throw JSONRPCError(-11, "Invalid account name");
+ return strAccount;
+}
+
+
+
+///
+/// Note: This interface may still be subject to change.
+///
+
+
+Value help(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() > 1)
+ throw runtime_error(
+ "help [command]\n"
+ "List commands, or get help for a command.");
+
+ string strCommand;
+ if (params.size() > 0)
+ strCommand = params[0].get_str();
+
+ string strRet;
+ set<rpcfn_type> setDone;
+ for (map<string, rpcfn_type>::iterator mi = mapCallTable.begin(); mi != mapCallTable.end(); ++mi)
+ {
+ string strMethod = (*mi).first;
+ // We already filter duplicates, but these deprecated screw up the sort order
+ if (strMethod == "getamountreceived" ||
+ strMethod == "getallreceived" ||
+ (strMethod.find("label") != string::npos))
+ continue;
+ if (strCommand != "" && strMethod != strCommand)
+ continue;
+ try
+ {
+ Array params;
+ rpcfn_type pfn = (*mi).second;
+ if (setDone.insert(pfn).second)
+ (*pfn)(params, true);
+ }
+ catch (std::exception& e)
+ {
+ // Help text is returned in an exception
+ string strHelp = string(e.what());
+ if (strCommand == "")
+ if (strHelp.find('\n') != -1)
+ strHelp = strHelp.substr(0, strHelp.find('\n'));
+ strRet += strHelp + "\n";
+ }
+ }
+ if (strRet == "")
+ strRet = strprintf("help: unknown command: %s\n", strCommand.c_str());
+ strRet = strRet.substr(0,strRet.size()-1);
+ return strRet;
+}
+
+
+Value stop(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() != 0)
+ throw runtime_error(
+ "stop\n"
+ "Stop bitcoin server.");
+
+ // Shutdown will take long enough that the response should get back
+ CreateThread(Shutdown, NULL);
+ return "bitcoin server stopping";
+}
+
+
+Value getblockcount(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() != 0)
+ throw runtime_error(
+ "getblockcount\n"
+ "Returns the number of blocks in the longest block chain.");
+
+ return nBestHeight;
+}
+
+
+Value getblocknumber(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() != 0)
+ throw runtime_error(
+ "getblocknumber\n"
+ "Returns the block number of the latest block in the longest block chain.");
+
+ return nBestHeight;
+}
+
+
+Value getconnectioncount(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() != 0)
+ throw runtime_error(
+ "getconnectioncount\n"
+ "Returns the number of connections to other nodes.");
+
+ return (int)vNodes.size();
+}
+
+
+double GetDifficulty()
+{
+ // Floating point number that is a multiple of the minimum difficulty,
+ // minimum difficulty = 1.0.
+ if (pindexBest == NULL)
+ return 1.0;
+ int nShift = 256 - 32 - 31; // to fit in a uint
+ double dMinimum = (CBigNum().SetCompact(bnProofOfWorkLimit.GetCompact()) >> nShift).getuint();
+ double dCurrently = (CBigNum().SetCompact(pindexBest->nBits) >> nShift).getuint();
+ return dMinimum / dCurrently;
+}
+
+Value getdifficulty(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() != 0)
+ throw runtime_error(
+ "getdifficulty\n"
+ "Returns the proof-of-work difficulty as a multiple of the minimum difficulty.");
+
+ return GetDifficulty();
+}
+
+
+Value getgenerate(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() != 0)
+ throw runtime_error(
+ "getgenerate\n"
+ "Returns true or false.");
+
+ return (bool)fGenerateBitcoins;
+}
+
+
+Value setgenerate(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() < 1 || params.size() > 2)
+ throw runtime_error(
+ "setgenerate <generate> [genproclimit]\n"
+ "<generate> is true or false to turn generation on or off.\n"
+ "Generation is limited to [genproclimit] processors, -1 is unlimited.");
+
+ bool fGenerate = true;
+ if (params.size() > 0)
+ fGenerate = params[0].get_bool();
+
+ if (params.size() > 1)
+ {
+ int nGenProcLimit = params[1].get_int();
+ fLimitProcessors = (nGenProcLimit != -1);
+ CWalletDB().WriteSetting("fLimitProcessors", fLimitProcessors);
+ if (nGenProcLimit != -1)
+ CWalletDB().WriteSetting("nLimitProcessors", nLimitProcessors = nGenProcLimit);
+ if (nGenProcLimit == 0)
+ fGenerate = false;
+ }
+
+ GenerateBitcoins(fGenerate);
+ return Value::null;
+}
+
+
+Value gethashespersec(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() != 0)
+ throw runtime_error(
+ "gethashespersec\n"
+ "Returns a recent hashes per second performance measurement while generating.");
+
+ if (GetTimeMillis() - nHPSTimerStart > 8000)
+ return (boost::int64_t)0;
+ return (boost::int64_t)dHashesPerSec;
+}
+
+
+Value getinfo(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() != 0)
+ throw runtime_error(
+ "getinfo\n"
+ "Returns an object containing various state info.");
+
+ Object obj;
+ obj.push_back(Pair("version", (int)VERSION));
+ obj.push_back(Pair("balance", ValueFromAmount(GetBalance())));
+ obj.push_back(Pair("blocks", (int)nBestHeight));
+ obj.push_back(Pair("connections", (int)vNodes.size()));
+ obj.push_back(Pair("proxy", (fUseProxy ? addrProxy.ToStringIPPort() : string())));
+ obj.push_back(Pair("generate", (bool)fGenerateBitcoins));
+ obj.push_back(Pair("genproclimit", (int)(fLimitProcessors ? nLimitProcessors : -1)));
+ obj.push_back(Pair("difficulty", (double)GetDifficulty()));
+ obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
+ obj.push_back(Pair("testnet", fTestNet));
+ obj.push_back(Pair("keypoololdest", (boost::int64_t)GetOldestKeyPoolTime()));
+ obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee)));
+ obj.push_back(Pair("errors", GetWarnings("statusbar")));
+ return obj;
+}
+
+
+Value getnewaddress(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() > 1)
+ throw runtime_error(
+ "getnewaddress [account]\n"
+ "Returns a new bitcoin address for receiving payments. "
+ "If [account] is specified (recommended), it is added to the address book "
+ "so payments received with the address will be credited to [account].");
+
+ // Parse the account first so we don't generate a key if there's an error
+ string strAccount;
+ if (params.size() > 0)
+ strAccount = AccountFromValue(params[0]);
+
+ // Generate a new key that is added to wallet
+ string strAddress = PubKeyToAddress(GetKeyFromKeyPool());
+
+ SetAddressBookName(strAddress, strAccount);
+ return strAddress;
+}
+
+
+// requires cs_main, cs_mapWallet locks
+string GetAccountAddress(string strAccount, bool bForceNew=false)
+{
+ string strAddress;
+
+ CWalletDB walletdb;
+ walletdb.TxnBegin();
+
+ CAccount account;
+ walletdb.ReadAccount(strAccount, account);
+
+ // Check if the current key has been used
+ if (!account.vchPubKey.empty())
+ {
+ CScript scriptPubKey;
+ scriptPubKey.SetBitcoinAddress(account.vchPubKey);
+ for (map<uint256, CWalletTx>::iterator it = mapWallet.begin();
+ it != mapWallet.end() && !account.vchPubKey.empty();
+ ++it)
+ {
+ const CWalletTx& wtx = (*it).second;
+ BOOST_FOREACH(const CTxOut& txout, wtx.vout)
+ if (txout.scriptPubKey == scriptPubKey)
+ account.vchPubKey.clear();
+ }
+ }
+
+ // Generate a new key
+ if (account.vchPubKey.empty() || bForceNew)
+ {
+ account.vchPubKey = GetKeyFromKeyPool();
+ string strAddress = PubKeyToAddress(account.vchPubKey);
+ SetAddressBookName(strAddress, strAccount);
+ walletdb.WriteAccount(strAccount, account);
+ }
+
+ walletdb.TxnCommit();
+ strAddress = PubKeyToAddress(account.vchPubKey);
+
+ return strAddress;
+}
+
+Value getaccountaddress(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() != 1)
+ throw runtime_error(
+ "getaccountaddress <account>\n"
+ "Returns the current bitcoin address for receiving payments to this account.");
+
+ // Parse the account first so we don't generate a key if there's an error
+ string strAccount = AccountFromValue(params[0]);
+
+ Value ret;
+
+ CRITICAL_BLOCK(cs_main)
+ CRITICAL_BLOCK(cs_mapWallet)
+ {
+ ret = GetAccountAddress(strAccount);
+ }
+
+ return ret;
+}
+
+
+
+Value setaccount(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() < 1 || params.size() > 2)
+ throw runtime_error(
+ "setaccount <bitcoinaddress> <account>\n"
+ "Sets the account associated with the given address.");
+
+ string strAddress = params[0].get_str();
+ uint160 hash160;
+ bool isValid = AddressToHash160(strAddress, hash160);
+ if (!isValid)
+ throw JSONRPCError(-5, "Invalid bitcoin address");
+
+
+ string strAccount;
+ if (params.size() > 1)
+ strAccount = AccountFromValue(params[1]);
+
+ // Detect when changing the account of an address that is the 'unused current key' of another account:
+ CRITICAL_BLOCK(cs_main)
+ CRITICAL_BLOCK(cs_mapWallet)
+ CRITICAL_BLOCK(cs_mapAddressBook)
+ {
+ if (mapAddressBook.count(strAddress))
+ {
+ string strOldAccount = mapAddressBook[strAddress];
+ if (strAddress == GetAccountAddress(strOldAccount))
+ GetAccountAddress(strOldAccount, true);
+ }
+ }
+
+ SetAddressBookName(strAddress, strAccount);
+ return Value::null;
+}
+
+
+Value getaccount(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() != 1)
+ throw runtime_error(
+ "getaccount <bitcoinaddress>\n"
+ "Returns the account associated with the given address.");
+
+ string strAddress = params[0].get_str();
+
+ string strAccount;
+ CRITICAL_BLOCK(cs_mapAddressBook)
+ {
+ map<string, string>::iterator mi = mapAddressBook.find(strAddress);
+ if (mi != mapAddressBook.end() && !(*mi).second.empty())
+ strAccount = (*mi).second;
+ }
+ return strAccount;
+}
+
+
+Value getaddressesbyaccount(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() != 1)
+ throw runtime_error(
+ "getaddressesbyaccount <account>\n"
+ "Returns the list of addresses for the given account.");
+
+ string strAccount = AccountFromValue(params[0]);
+
+ // Find all addresses that have the given account
+ Array ret;
+ CRITICAL_BLOCK(cs_mapAddressBook)
+ {
+ BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapAddressBook)
+ {
+ const string& strAddress = item.first;
+ const string& strName = item.second;
+ if (strName == strAccount)
+ {
+ // We're only adding valid bitcoin addresses and not ip addresses
+ CScript scriptPubKey;
+ if (scriptPubKey.SetBitcoinAddress(strAddress))
+ ret.push_back(strAddress);
+ }
+ }
+ }
+ return ret;
+}
+
+Value settxfee(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() < 1 || params.size() > 1)
+ throw runtime_error(
+ "settxfee <amount>\n"
+ "<amount> is a real and is rounded to the nearest 0.00000001");
+
+ // Amount
+ int64 nAmount = 0;
+ if (params[0].get_real() != 0.0)
+ nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts
+
+ nTransactionFee = nAmount;
+ return true;
+}
+
+Value sendtoaddress(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() < 2 || params.size() > 4)
+ throw runtime_error(
+ "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
+ "<amount> is a real and is rounded to the nearest 0.00000001");
+
+ string strAddress = params[0].get_str();
+
+ // Amount
+ int64 nAmount = AmountFromValue(params[1]);
+
+ // Wallet comments
+ CWalletTx wtx;
+ if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
+ wtx.mapValue["comment"] = params[2].get_str();
+ if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
+ wtx.mapValue["to"] = params[3].get_str();
+
+ CRITICAL_BLOCK(cs_main)
+ {
+ string strError = SendMoneyToBitcoinAddress(strAddress, nAmount, wtx);
+ if (strError != "")
+ throw JSONRPCError(-4, strError);
+ }
+
+ return wtx.GetHash().GetHex();
+}
+
+
+Value getreceivedbyaddress(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() < 1 || params.size() > 2)
+ throw runtime_error(
+ "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
+ "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
+
+ // Bitcoin address
+ string strAddress = params[0].get_str();
+ CScript scriptPubKey;
+ if (!scriptPubKey.SetBitcoinAddress(strAddress))
+ throw JSONRPCError(-5, "Invalid bitcoin address");
+ if (!IsMine(scriptPubKey))
+ return (double)0.0;
+
+ // Minimum confirmations
+ int nMinDepth = 1;
+ if (params.size() > 1)
+ nMinDepth = params[1].get_int();
+
+ // Tally
+ int64 nAmount = 0;
+ CRITICAL_BLOCK(cs_mapWallet)
+ {
+ for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ {
+ const CWalletTx& wtx = (*it).second;
+ if (wtx.IsCoinBase() || !wtx.IsFinal())
+ continue;
+
+ BOOST_FOREACH(const CTxOut& txout, wtx.vout)
+ if (txout.scriptPubKey == scriptPubKey)
+ if (wtx.GetDepthInMainChain() >= nMinDepth)
+ nAmount += txout.nValue;
+ }
+ }
+
+ return ValueFromAmount(nAmount);
+}
+
+
+void GetAccountPubKeys(string strAccount, set<CScript>& setPubKey)
+{
+ CRITICAL_BLOCK(cs_mapAddressBook)
+ {
+ BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapAddressBook)
+ {
+ const string& strAddress = item.first;
+ const string& strName = item.second;
+ if (strName == strAccount)
+ {
+ // We're only counting our own valid bitcoin addresses and not ip addresses
+ CScript scriptPubKey;
+ if (scriptPubKey.SetBitcoinAddress(strAddress))
+ if (IsMine(scriptPubKey))
+ setPubKey.insert(scriptPubKey);
+ }
+ }
+ }
+}
+
+
+Value getreceivedbyaccount(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() < 1 || params.size() > 2)
+ throw runtime_error(
+ "getreceivedbyaccount <account> [minconf=1]\n"
+ "Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.");
+
+ // Minimum confirmations
+ int nMinDepth = 1;
+ if (params.size() > 1)
+ nMinDepth = params[1].get_int();
+
+ // Get the set of pub keys that have the label
+ string strAccount = AccountFromValue(params[0]);
+ set<CScript> setPubKey;
+ GetAccountPubKeys(strAccount, setPubKey);
+
+ // Tally
+ int64 nAmount = 0;
+ CRITICAL_BLOCK(cs_mapWallet)
+ {
+ for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ {
+ const CWalletTx& wtx = (*it).second;
+ if (wtx.IsCoinBase() || !wtx.IsFinal())
+ continue;
+
+ BOOST_FOREACH(const CTxOut& txout, wtx.vout)
+ if (setPubKey.count(txout.scriptPubKey))
+ if (wtx.GetDepthInMainChain() >= nMinDepth)
+ nAmount += txout.nValue;
+ }
+ }
+
+ return (double)nAmount / (double)COIN;
+}
+
+
+int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
+{
+ int64 nBalance = 0;
+ CRITICAL_BLOCK(cs_mapWallet)
+ {
+ // Tally wallet transactions
+ for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ {
+ const CWalletTx& wtx = (*it).second;
+ if (!wtx.IsFinal())
+ continue;
+
+ int64 nGenerated, nReceived, nSent, nFee;
+ wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
+
+ if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
+ nBalance += nReceived;
+ nBalance += nGenerated - nSent - nFee;
+ }
+
+ // Tally internal accounting entries
+ nBalance += walletdb.GetAccountCreditDebit(strAccount);
+ }
+
+ return nBalance;
+}
+
+int64 GetAccountBalance(const string& strAccount, int nMinDepth)
+{
+ CWalletDB walletdb;
+ return GetAccountBalance(walletdb, strAccount, nMinDepth);
+}
+
+
+Value getbalance(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() < 0 || params.size() > 2)
+ throw runtime_error(
+ "getbalance [account] [minconf=1]\n"
+ "If [account] is not specified, returns the server's total available balance.\n"
+ "If [account] is specified, returns the balance in the account.");
+
+ if (params.size() == 0)
+ return ValueFromAmount(GetBalance());
+
+ int nMinDepth = 1;
+ if (params.size() > 1)
+ nMinDepth = params[1].get_int();
+
+ if (params[0].get_str() == "*") {
+ // Calculate total balance a different way from GetBalance()
+ // (GetBalance() sums up all unspent TxOuts)
+ // getbalance and getbalance '*' should always return the same number.
+ int64 nBalance = 0;
+ for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ {
+ const CWalletTx& wtx = (*it).second;
+ if (!wtx.IsFinal())
+ continue;
+
+ int64 allGeneratedImmature, allGeneratedMature, allFee;
+ allGeneratedImmature = allGeneratedMature = allFee = 0;
+ string strSentAccount;
+ list<pair<string, int64> > listReceived;
+ list<pair<string, int64> > listSent;
+ wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
+ if (wtx.GetDepthInMainChain() >= nMinDepth)
+ BOOST_FOREACH(const PAIRTYPE(string,int64)& r, listReceived)
+ nBalance += r.second;
+ BOOST_FOREACH(const PAIRTYPE(string,int64)& r, listSent)
+ nBalance -= r.second;
+ nBalance -= allFee;
+ nBalance += allGeneratedMature;
+ }
+ return ValueFromAmount(nBalance);
+ }
+
+ string strAccount = AccountFromValue(params[0]);
+
+ int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
+
+ return ValueFromAmount(nBalance);
+}
+
+
+Value movecmd(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() < 3 || params.size() > 5)
+ throw runtime_error(
+ "move <fromaccount> <toaccount> <amount> [minconf=1] [comment]\n"
+ "Move from one account in your wallet to another.");
+
+ string strFrom = AccountFromValue(params[0]);
+ string strTo = AccountFromValue(params[1]);
+ int64 nAmount = AmountFromValue(params[2]);
+ int nMinDepth = 1;
+ if (params.size() > 3)
+ nMinDepth = params[3].get_int();
+ string strComment;
+ if (params.size() > 4)
+ strComment = params[4].get_str();
+
+ CRITICAL_BLOCK(cs_mapWallet)
+ {
+ CWalletDB walletdb;
+ walletdb.TxnBegin();
+
+ int64 nNow = GetAdjustedTime();
+
+ // Debit
+ CAccountingEntry debit;
+ debit.strAccount = strFrom;
+ debit.nCreditDebit = -nAmount;
+ debit.nTime = nNow;
+ debit.strOtherAccount = strTo;
+ debit.strComment = strComment;
+ walletdb.WriteAccountingEntry(debit);
+
+ // Credit
+ CAccountingEntry credit;
+ credit.strAccount = strTo;
+ credit.nCreditDebit = nAmount;
+ credit.nTime = nNow;
+ credit.strOtherAccount = strFrom;
+ credit.strComment = strComment;
+ walletdb.WriteAccountingEntry(credit);
+
+ walletdb.TxnCommit();
+ }
+ return true;
+}
+
+
+Value sendfrom(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() < 3 || params.size() > 6)
+ throw runtime_error(
+ "sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to]\n"
+ "<amount> is a real and is rounded to the nearest 0.00000001");
+
+ string strAccount = AccountFromValue(params[0]);
+ string strAddress = params[1].get_str();
+ int64 nAmount = AmountFromValue(params[2]);
+ int nMinDepth = 1;
+ if (params.size() > 3)
+ nMinDepth = params[3].get_int();
+
+ CWalletTx wtx;
+ wtx.strFromAccount = strAccount;
+ if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
+ wtx.mapValue["comment"] = params[4].get_str();
+ if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
+ wtx.mapValue["to"] = params[5].get_str();
+
+ CRITICAL_BLOCK(cs_main)
+ CRITICAL_BLOCK(cs_mapWallet)
+ {
+ // Check funds
+ int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
+ if (nAmount > nBalance)
+ throw JSONRPCError(-6, "Account has insufficient funds");
+
+ // Send
+ string strError = SendMoneyToBitcoinAddress(strAddress, nAmount, wtx);
+ if (strError != "")
+ throw JSONRPCError(-4, strError);
+ }
+
+ return wtx.GetHash().GetHex();
+}
+
+Value sendmany(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() < 2 || params.size() > 4)
+ throw runtime_error(
+ "sendmany <fromaccount> {address:amount,...} [minconf=1] [comment]\n"
+ "amounts are double-precision floating point numbers");
+
+ string strAccount = AccountFromValue(params[0]);
+ Object sendTo = params[1].get_obj();
+ int nMinDepth = 1;
+ if (params.size() > 2)
+ nMinDepth = params[2].get_int();
+
+ CWalletTx wtx;
+ wtx.strFromAccount = strAccount;
+ if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
+ wtx.mapValue["comment"] = params[3].get_str();
+
+ set<string> setAddress;
+ vector<pair<CScript, int64> > vecSend;
+
+ int64 totalAmount = 0;
+ BOOST_FOREACH(const Pair& s, sendTo)
+ {
+ uint160 hash160;
+ string strAddress = s.name_;
+
+ if (setAddress.count(strAddress))
+ throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+strAddress);
+ setAddress.insert(strAddress);
+
+ CScript scriptPubKey;
+ if (!scriptPubKey.SetBitcoinAddress(strAddress))
+ throw JSONRPCError(-5, string("Invalid bitcoin address:")+strAddress);
+ int64 nAmount = AmountFromValue(s.value_);
+ totalAmount += nAmount;
+
+ vecSend.push_back(make_pair(scriptPubKey, nAmount));
+ }
+
+ CRITICAL_BLOCK(cs_main)
+ CRITICAL_BLOCK(cs_mapWallet)
+ {
+ // Check funds
+ int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
+ if (totalAmount > nBalance)
+ throw JSONRPCError(-6, "Account has insufficient funds");
+
+ // Send
+ CReserveKey keyChange;
+ int64 nFeeRequired = 0;
+ bool fCreated = CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
+ if (!fCreated)
+ {
+ if (totalAmount + nFeeRequired > GetBalance())
+ throw JSONRPCError(-6, "Insufficient funds");
+ throw JSONRPCError(-4, "Transaction creation failed");
+ }
+ if (!CommitTransaction(wtx, keyChange))
+ throw JSONRPCError(-4, "Transaction commit failed");
+ }
+
+ return wtx.GetHash().GetHex();
+}
+
+
+struct tallyitem
+{
+ int64 nAmount;
+ int nConf;
+ tallyitem()
+ {
+ nAmount = 0;
+ nConf = INT_MAX;
+ }
+};
+
+Value ListReceived(const Array& params, bool fByAccounts)
+{
+ // Minimum confirmations
+ int nMinDepth = 1;
+ if (params.size() > 0)
+ nMinDepth = params[0].get_int();
+
+ // Whether to include empty accounts
+ bool fIncludeEmpty = false;
+ if (params.size() > 1)
+ fIncludeEmpty = params[1].get_bool();
+
+ // Tally
+ map<uint160, tallyitem> mapTally;
+ CRITICAL_BLOCK(cs_mapWallet)
+ {
+ for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ {
+ const CWalletTx& wtx = (*it).second;
+ if (wtx.IsCoinBase() || !wtx.IsFinal())
+ continue;
+
+ int nDepth = wtx.GetDepthInMainChain();
+ if (nDepth < nMinDepth)
+ continue;
+
+ BOOST_FOREACH(const CTxOut& txout, wtx.vout)
+ {
+ // Only counting our own bitcoin addresses and not ip addresses
+ uint160 hash160 = txout.scriptPubKey.GetBitcoinAddressHash160();
+ if (hash160 == 0 || !mapPubKeys.count(hash160)) // IsMine
+ continue;
+
+ tallyitem& item = mapTally[hash160];
+ item.nAmount += txout.nValue;
+ item.nConf = min(item.nConf, nDepth);
+ }
+ }
+ }
+
+ // Reply
+ Array ret;
+ map<string, tallyitem> mapAccountTally;
+ CRITICAL_BLOCK(cs_mapAddressBook)
+ {
+ BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapAddressBook)
+ {
+ const string& strAddress = item.first;
+ const string& strAccount = item.second;
+ uint160 hash160;
+ if (!AddressToHash160(strAddress, hash160))
+ continue;
+ map<uint160, tallyitem>::iterator it = mapTally.find(hash160);
+ if (it == mapTally.end() && !fIncludeEmpty)
+ continue;
+
+ int64 nAmount = 0;
+ int nConf = INT_MAX;
+ if (it != mapTally.end())
+ {
+ nAmount = (*it).second.nAmount;
+ nConf = (*it).second.nConf;
+ }
+
+ if (fByAccounts)
+ {
+ tallyitem& item = mapAccountTally[strAccount];
+ item.nAmount += nAmount;
+ item.nConf = min(item.nConf, nConf);
+ }
+ else
+ {
+ Object obj;
+ obj.push_back(Pair("address", strAddress));
+ obj.push_back(Pair("account", strAccount));
+ obj.push_back(Pair("label", strAccount)); // deprecated
+ obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
+ obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
+ ret.push_back(obj);
+ }
+ }
+ }
+
+ if (fByAccounts)
+ {
+ for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
+ {
+ int64 nAmount = (*it).second.nAmount;
+ int nConf = (*it).second.nConf;
+ Object obj;
+ obj.push_back(Pair("account", (*it).first));
+ obj.push_back(Pair("label", (*it).first)); // deprecated
+ obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
+ obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
+ ret.push_back(obj);
+ }
+ }
+
+ return ret;
+}
+
+Value listreceivedbyaddress(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() > 2)
+ throw runtime_error(
+ "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
+ "[minconf] is the minimum number of confirmations before payments are included.\n"
+ "[includeempty] whether to include addresses that haven't received any payments.\n"
+ "Returns an array of objects containing:\n"
+ " \"address\" : receiving address\n"
+ " \"account\" : the account of the receiving address\n"
+ " \"amount\" : total amount received by the address\n"
+ " \"confirmations\" : number of confirmations of the most recent transaction included");
+
+ return ListReceived(params, false);
+}
+
+Value listreceivedbyaccount(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() > 2)
+ throw runtime_error(
+ "listreceivedbyaccount [minconf=1] [includeempty=false]\n"
+ "[minconf] is the minimum number of confirmations before payments are included.\n"
+ "[includeempty] whether to include accounts that haven't received any payments.\n"
+ "Returns an array of objects containing:\n"
+ " \"account\" : the account of the receiving addresses\n"
+ " \"amount\" : total amount received by addresses with this account\n"
+ " \"confirmations\" : number of confirmations of the most recent transaction included");
+
+ return ListReceived(params, true);
+}
+
+void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret)
+{
+ int64 nGeneratedImmature, nGeneratedMature, nFee;
+ string strSentAccount;
+ list<pair<string, int64> > listReceived;
+ list<pair<string, int64> > listSent;
+ wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
+
+ bool fAllAccounts = (strAccount == string("*"));
+
+ // Generated blocks assigned to account ""
+ if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == ""))
+ {
+ Object entry;
+ entry.push_back(Pair("account", string("")));
+ if (nGeneratedImmature)
+ {
+ entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan"));
+ entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature)));
+ }
+ else
+ {
+ entry.push_back(Pair("category", "generate"));
+ entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature)));
+ }
+ if (fLong)
+ WalletTxToJSON(wtx, entry);
+ ret.push_back(entry);
+ }
+
+ // Sent
+ if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
+ {
+ BOOST_FOREACH(const PAIRTYPE(string, int64)& s, listSent)
+ {
+ Object entry;
+ entry.push_back(Pair("account", strSentAccount));
+ entry.push_back(Pair("address", s.first));
+ entry.push_back(Pair("category", "send"));
+ entry.push_back(Pair("amount", ValueFromAmount(-s.second)));
+ entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
+ if (fLong)
+ WalletTxToJSON(wtx, entry);
+ ret.push_back(entry);
+ }
+ }
+
+ // Received
+ if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
+ CRITICAL_BLOCK(cs_mapAddressBook)
+ {
+ BOOST_FOREACH(const PAIRTYPE(string, int64)& r, listReceived)
+ {
+ string account;
+ if (mapAddressBook.count(r.first))
+ account = mapAddressBook[r.first];
+ if (fAllAccounts || (account == strAccount))
+ {
+ Object entry;
+ entry.push_back(Pair("account", account));
+ entry.push_back(Pair("address", r.first));
+ entry.push_back(Pair("category", "receive"));
+ entry.push_back(Pair("amount", ValueFromAmount(r.second)));
+ if (fLong)
+ WalletTxToJSON(wtx, entry);
+ ret.push_back(entry);
+ }
+ }
+ }
+
+}
+
+void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
+{
+ bool fAllAccounts = (strAccount == string("*"));
+
+ if (fAllAccounts || acentry.strAccount == strAccount)
+ {
+ Object entry;
+ entry.push_back(Pair("account", acentry.strAccount));
+ entry.push_back(Pair("category", "move"));
+ entry.push_back(Pair("time", (boost::int64_t)acentry.nTime));
+ entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
+ entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
+ entry.push_back(Pair("comment", acentry.strComment));
+ ret.push_back(entry);
+ }
+}
+
+Value listtransactions(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() > 3)
+ throw runtime_error(
+ "listtransactions [account] [count=10] [from=0]\n"
+ "Returns up to [count] most recent transactions skipping the first [from] transactions for account [account].");
+
+ string strAccount = "*";
+ if (params.size() > 0)
+ strAccount = params[0].get_str();
+ int nCount = 10;
+ if (params.size() > 1)
+ nCount = params[1].get_int();
+ int nFrom = 0;
+ if (params.size() > 2)
+ nFrom = params[2].get_int();
+
+ Array ret;
+ CWalletDB walletdb;
+
+ CRITICAL_BLOCK(cs_mapWallet)
+ {
+ // Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap:
+ typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
+ typedef multimap<int64, TxPair > TxItems;
+ TxItems txByTime;
+
+ for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ {
+ CWalletTx* wtx = &((*it).second);
+ txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
+ }
+ list<CAccountingEntry> acentries;
+ walletdb.ListAccountCreditDebit(strAccount, acentries);
+ BOOST_FOREACH(CAccountingEntry& entry, acentries)
+ {
+ txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
+ }
+
+ // Now: iterate backwards until we have nCount items to return:
+ TxItems::reverse_iterator it = txByTime.rbegin();
+ for (std::advance(it, nFrom); it != txByTime.rend(); ++it)
+ {
+ CWalletTx *const pwtx = (*it).second.first;
+ if (pwtx != 0)
+ ListTransactions(*pwtx, strAccount, 0, true, ret);
+ CAccountingEntry *const pacentry = (*it).second.second;
+ if (pacentry != 0)
+ AcentryToJSON(*pacentry, strAccount, ret);
+
+ if (ret.size() >= nCount) break;
+ }
+ // ret is now newest to oldest
+ }
+
+ // Make sure we return only last nCount items (sends-to-self might give us an extra):
+ if (ret.size() > nCount)
+ {
+ Array::iterator last = ret.begin();
+ std::advance(last, nCount);
+ ret.erase(last, ret.end());
+ }
+ std::reverse(ret.begin(), ret.end()); // oldest to newest
+
+ return ret;
+}
+
+Value listaccounts(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() > 1)
+ throw runtime_error(
+ "listaccounts [minconf=1]\n"
+ "Returns Object that has account names as keys, account balances as values.");
+
+ int nMinDepth = 1;
+ if (params.size() > 0)
+ nMinDepth = params[0].get_int();
+
+ map<string, int64> mapAccountBalances;
+ CRITICAL_BLOCK(cs_mapWallet)
+ CRITICAL_BLOCK(cs_mapAddressBook)
+ {
+ BOOST_FOREACH(const PAIRTYPE(string, string)& entry, mapAddressBook) {
+ uint160 hash160;
+ if(AddressToHash160(entry.first, hash160) && mapPubKeys.count(hash160)) // This address belongs to me
+ mapAccountBalances[entry.second] = 0;
+ }
+
+ for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ {
+ const CWalletTx& wtx = (*it).second;
+ int64 nGeneratedImmature, nGeneratedMature, nFee;
+ string strSentAccount;
+ list<pair<string, int64> > listReceived;
+ list<pair<string, int64> > listSent;
+ wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
+ mapAccountBalances[strSentAccount] -= nFee;
+ BOOST_FOREACH(const PAIRTYPE(string, int64)& s, listSent)
+ mapAccountBalances[strSentAccount] -= s.second;
+ if (wtx.GetDepthInMainChain() >= nMinDepth)
+ {
+ mapAccountBalances[""] += nGeneratedMature;
+ BOOST_FOREACH(const PAIRTYPE(string, int64)& r, listReceived)
+ if (mapAddressBook.count(r.first))
+ mapAccountBalances[mapAddressBook[r.first]] += r.second;
+ else
+ mapAccountBalances[""] += r.second;
+ }
+ }
+ }
+
+ list<CAccountingEntry> acentries;
+ CWalletDB().ListAccountCreditDebit("*", acentries);
+ BOOST_FOREACH(const CAccountingEntry& entry, acentries)
+ mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
+
+ Object ret;
+ BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) {
+ ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
+ }
+ return ret;
+}
+
+Value gettransaction(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() != 1)
+ throw runtime_error(
+ "gettransaction <txid>\n"
+ "Get detailed information about <txid>");
+
+ uint256 hash;
+ hash.SetHex(params[0].get_str());
+
+ Object entry;
+ CRITICAL_BLOCK(cs_mapWallet)
+ {
+ if (!mapWallet.count(hash))
+ throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
+ const CWalletTx& wtx = mapWallet[hash];
+
+ int64 nCredit = wtx.GetCredit();
+ int64 nDebit = wtx.GetDebit();
+ int64 nNet = nCredit - nDebit;
+ int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
+
+ entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
+ if (wtx.IsFromMe())
+ entry.push_back(Pair("fee", ValueFromAmount(nFee)));
+
+ WalletTxToJSON(mapWallet[hash], entry);
+
+ Array details;
+ ListTransactions(mapWallet[hash], "*", 0, false, details);
+ entry.push_back(Pair("details", details));
+ }
+
+ return entry;
+}
+
+
+Value backupwallet(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() != 1)
+ throw runtime_error(
+ "backupwallet <destination>\n"
+ "Safely copies wallet.dat to destination, which can be a directory or a path with filename.");
+
+ string strDest = params[0].get_str();
+ BackupWallet(strDest);
+
+ return Value::null;
+}
+
+
+Value validateaddress(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() != 1)
+ throw runtime_error(
+ "validateaddress <bitcoinaddress>\n"
+ "Return information about <bitcoinaddress>.");
+
+ string strAddress = params[0].get_str();
+ uint160 hash160;
+ bool isValid = AddressToHash160(strAddress, hash160);
+
+ Object ret;
+ ret.push_back(Pair("isvalid", isValid));
+ if (isValid)
+ {
+ // Call Hash160ToAddress() so we always return current ADDRESSVERSION
+ // version of the address:
+ string currentAddress = Hash160ToAddress(hash160);
+ ret.push_back(Pair("address", currentAddress));
+ ret.push_back(Pair("ismine", (mapPubKeys.count(hash160) > 0)));
+ CRITICAL_BLOCK(cs_mapAddressBook)
+ {
+ if (mapAddressBook.count(currentAddress))
+ ret.push_back(Pair("account", mapAddressBook[currentAddress]));
+ }
+ }
+ return ret;
+}
+
+
+Value getwork(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() > 1)
+ throw runtime_error(
+ "getwork [data]\n"
+ "If [data] is not specified, returns formatted hash data to work on:\n"
+ " \"midstate\" : precomputed hash state after hashing the first half of the data\n"
+ " \"data\" : block data\n"
+ " \"hash1\" : formatted hash buffer for second hash\n"
+ " \"target\" : little endian hash target\n"
+ "If [data] is specified, tries to solve the block and returns true if it was successful.");
+
+ if (vNodes.empty())
+ throw JSONRPCError(-9, "Bitcoin is not connected!");
+
+ if (IsInitialBlockDownload())
+ throw JSONRPCError(-10, "Bitcoin is downloading blocks...");
+
+ static map<uint256, pair<CBlock*, unsigned int> > mapNewBlock;
+ static vector<CBlock*> vNewBlock;
+ static CReserveKey reservekey;
+
+ if (params.size() == 0)
+ {
+ // Update block
+ static unsigned int nTransactionsUpdatedLast;
+ static CBlockIndex* pindexPrev;
+ static int64 nStart;
+ static CBlock* pblock;
+ if (pindexPrev != pindexBest ||
+ (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
+ {
+ if (pindexPrev != pindexBest)
+ {
+ // Deallocate old blocks since they're obsolete now
+ mapNewBlock.clear();
+ BOOST_FOREACH(CBlock* pblock, vNewBlock)
+ delete pblock;
+ vNewBlock.clear();
+ }
+ nTransactionsUpdatedLast = nTransactionsUpdated;
+ pindexPrev = pindexBest;
+ nStart = GetTime();
+
+ // Create new block
+ pblock = CreateNewBlock(reservekey);
+ if (!pblock)
+ throw JSONRPCError(-7, "Out of memory");
+ vNewBlock.push_back(pblock);
+ }
+
+ // Update nTime
+ pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
+ pblock->nNonce = 0;
+
+ // Update nExtraNonce
+ static unsigned int nExtraNonce = 0;
+ static int64 nPrevTime = 0;
+ IncrementExtraNonce(pblock, pindexPrev, nExtraNonce, nPrevTime);
+
+ // Save
+ mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, nExtraNonce);
+
+ // Prebuild hash buffers
+ char pmidstate[32];
+ char pdata[128];
+ char phash1[64];
+ FormatHashBuffers(pblock, pmidstate, pdata, phash1);
+
+ uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
+
+ Object result;
+ result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate))));
+ result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
+ result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1))));
+ result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
+ return result;
+ }
+ else
+ {
+ // Parse parameters
+ vector<unsigned char> vchData = ParseHex(params[0].get_str());
+ if (vchData.size() != 128)
+ throw JSONRPCError(-8, "Invalid parameter");
+ CBlock* pdata = (CBlock*)&vchData[0];
+
+ // Byte reverse
+ for (int i = 0; i < 128/4; i++)
+ ((unsigned int*)pdata)[i] = CryptoPP::ByteReverse(((unsigned int*)pdata)[i]);
+
+ // Get saved block
+ if (!mapNewBlock.count(pdata->hashMerkleRoot))
+ return false;
+ CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
+ unsigned int nExtraNonce = mapNewBlock[pdata->hashMerkleRoot].second;
+
+ pblock->nTime = pdata->nTime;
+ pblock->nNonce = pdata->nNonce;
+ pblock->vtx[0].vin[0].scriptSig = CScript() << pblock->nBits << CBigNum(nExtraNonce);
+ pblock->hashMerkleRoot = pblock->BuildMerkleTree();
+
+ return CheckWork(pblock, reservekey);
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+//
+// Call Table
+//
+
+pair<string, rpcfn_type> pCallTable[] =
+{
+ make_pair("help", &help),
+ make_pair("stop", &stop),
+ make_pair("getblockcount", &getblockcount),
+ make_pair("getblocknumber", &getblocknumber),
+ make_pair("getconnectioncount", &getconnectioncount),
+ make_pair("getdifficulty", &getdifficulty),
+ make_pair("getgenerate", &getgenerate),
+ make_pair("setgenerate", &setgenerate),
+ make_pair("gethashespersec", &gethashespersec),
+ make_pair("getinfo", &getinfo),
+ make_pair("getnewaddress", &getnewaddress),
+ make_pair("getaccountaddress", &getaccountaddress),
+ make_pair("setaccount", &setaccount),
+ make_pair("setlabel", &setaccount), // deprecated
+ make_pair("getaccount", &getaccount),
+ make_pair("getlabel", &getaccount), // deprecated
+ make_pair("getaddressesbyaccount", &getaddressesbyaccount),
+ make_pair("getaddressesbylabel", &getaddressesbyaccount), // deprecated
+ make_pair("sendtoaddress", &sendtoaddress),
+ make_pair("getamountreceived", &getreceivedbyaddress), // deprecated, renamed to getreceivedbyaddress
+ make_pair("getallreceived", &listreceivedbyaddress), // deprecated, renamed to listreceivedbyaddress
+ make_pair("getreceivedbyaddress", &getreceivedbyaddress),
+ make_pair("getreceivedbyaccount", &getreceivedbyaccount),
+ make_pair("getreceivedbylabel", &getreceivedbyaccount), // deprecated
+ make_pair("listreceivedbyaddress", &listreceivedbyaddress),
+ make_pair("listreceivedbyaccount", &listreceivedbyaccount),
+ make_pair("listreceivedbylabel", &listreceivedbyaccount), // deprecated
+ make_pair("backupwallet", &backupwallet),
+ make_pair("validateaddress", &validateaddress),
+ make_pair("getbalance", &getbalance),
+ make_pair("move", &movecmd),
+ make_pair("sendfrom", &sendfrom),
+ make_pair("sendmany", &sendmany),
+ make_pair("gettransaction", &gettransaction),
+ make_pair("listtransactions", &listtransactions),
+ make_pair("getwork", &getwork),
+ make_pair("listaccounts", &listaccounts),
+ make_pair("settxfee", &settxfee),
+};
+map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
+
+string pAllowInSafeMode[] =
+{
+ "help",
+ "stop",
+ "getblockcount",
+ "getblocknumber",
+ "getconnectioncount",
+ "getdifficulty",
+ "getgenerate",
+ "setgenerate",
+ "gethashespersec",
+ "getinfo",
+ "getnewaddress",
+ "getaccountaddress",
+ "setlabel",
+ "getaccount",
+ "getlabel", // deprecated
+ "getaddressesbyaccount",
+ "getaddressesbylabel", // deprecated
+ "backupwallet",
+ "validateaddress",
+ "getwork",
+};
+set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
+
+
+
+
+//
+// HTTP protocol
+//
+// This ain't Apache. We're just using HTTP header for the length field
+// and to be compatible with other JSON-RPC implementations.
+//
+
+string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
+{
+ ostringstream s;
+ s << "POST / HTTP/1.1\r\n"
+ << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
+ << "Host: 127.0.0.1\r\n"
+ << "Content-Type: application/json\r\n"
+ << "Content-Length: " << strMsg.size() << "\r\n"
+ << "Accept: application/json\r\n";
+ BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
+ s << item.first << ": " << item.second << "\r\n";
+ s << "\r\n" << strMsg;
+
+ return s.str();
+}
+
+string rfc1123Time()
+{
+ char buffer[64];
+ time_t now;
+ time(&now);
+ struct tm* now_gmt = gmtime(&now);
+ string locale(setlocale(LC_TIME, NULL));
+ setlocale(LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
+ strftime(buffer, sizeof(buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
+ setlocale(LC_TIME, locale.c_str());
+ return string(buffer);
+}
+
+string HTTPReply(int nStatus, const string& strMsg)
+{
+ if (nStatus == 401)
+ return strprintf("HTTP/1.0 401 Authorization Required\r\n"
+ "Date: %s\r\n"
+ "Server: bitcoin-json-rpc/%s\r\n"
+ "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
+ "Content-Type: text/html\r\n"
+ "Content-Length: 296\r\n"
+ "\r\n"
+ "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
+ "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
+ "<HTML>\r\n"
+ "<HEAD>\r\n"
+ "<TITLE>Error</TITLE>\r\n"
+ "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
+ "</HEAD>\r\n"
+ "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
+ "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
+ string strStatus;
+ if (nStatus == 200) strStatus = "OK";
+ else if (nStatus == 400) strStatus = "Bad Request";
+ else if (nStatus == 404) strStatus = "Not Found";
+ else if (nStatus == 500) strStatus = "Internal Server Error";
+ return strprintf(
+ "HTTP/1.1 %d %s\r\n"
+ "Date: %s\r\n"
+ "Connection: close\r\n"
+ "Content-Length: %d\r\n"
+ "Content-Type: application/json\r\n"
+ "Server: bitcoin-json-rpc/%s\r\n"
+ "\r\n"
+ "%s",
+ nStatus,
+ strStatus.c_str(),
+ rfc1123Time().c_str(),
+ strMsg.size(),
+ FormatFullVersion().c_str(),
+ strMsg.c_str());
+}
+
+int ReadHTTPStatus(std::basic_istream<char>& stream)
+{
+ string str;
+ getline(stream, str);
+ vector<string> vWords;
+ boost::split(vWords, str, boost::is_any_of(" "));
+ if (vWords.size() < 2)
+ return 500;
+ return atoi(vWords[1].c_str());
+}
+
+int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
+{
+ int nLen = 0;
+ loop
+ {
+ string str;
+ std::getline(stream, str);
+ if (str.empty() || str == "\r")
+ break;
+ string::size_type nColon = str.find(":");
+ if (nColon != string::npos)
+ {
+ string strHeader = str.substr(0, nColon);
+ boost::trim(strHeader);
+ boost::to_lower(strHeader);
+ string strValue = str.substr(nColon+1);
+ boost::trim(strValue);
+ mapHeadersRet[strHeader] = strValue;
+ if (strHeader == "content-length")
+ nLen = atoi(strValue.c_str());
+ }
+ }
+ return nLen;
+}
+
+int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
+{
+ mapHeadersRet.clear();
+ strMessageRet = "";
+
+ // Read status
+ int nStatus = ReadHTTPStatus(stream);
+
+ // Read header
+ int nLen = ReadHTTPHeader(stream, mapHeadersRet);
+ if (nLen < 0 || nLen > MAX_SIZE)
+ return 500;
+
+ // Read message
+ if (nLen > 0)
+ {
+ vector<char> vch(nLen);
+ stream.read(&vch[0], nLen);
+ strMessageRet = string(vch.begin(), vch.end());
+ }
+
+ return nStatus;
+}
+
+string EncodeBase64(string s)
+{
+ BIO *b64, *bmem;
+ BUF_MEM *bptr;
+
+ b64 = BIO_new(BIO_f_base64());
+ BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
+ bmem = BIO_new(BIO_s_mem());
+ b64 = BIO_push(b64, bmem);
+ BIO_write(b64, s.c_str(), s.size());
+ BIO_flush(b64);
+ BIO_get_mem_ptr(b64, &bptr);
+
+ string result(bptr->data, bptr->length);
+ BIO_free_all(b64);
+
+ return result;
+}
+
+string DecodeBase64(string s)
+{
+ BIO *b64, *bmem;
+
+ char* buffer = static_cast<char*>(calloc(s.size(), sizeof(char)));
+
+ b64 = BIO_new(BIO_f_base64());
+ BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
+ bmem = BIO_new_mem_buf(const_cast<char*>(s.c_str()), s.size());
+ bmem = BIO_push(b64, bmem);
+ BIO_read(bmem, buffer, s.size());
+ BIO_free_all(bmem);
+
+ string result(buffer);
+ free(buffer);
+ return result;
+}
+
+bool HTTPAuthorized(map<string, string>& mapHeaders)
+{
+ string strAuth = mapHeaders["authorization"];
+ if (strAuth.substr(0,6) != "Basic ")
+ return false;
+ string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
+ string strUserPass = DecodeBase64(strUserPass64);
+ string::size_type nColon = strUserPass.find(":");
+ if (nColon == string::npos)
+ return false;
+ string strUser = strUserPass.substr(0, nColon);
+ string strPassword = strUserPass.substr(nColon+1);
+ return (strUser == mapArgs["-rpcuser"] && strPassword == mapArgs["-rpcpassword"]);
+}
+
+//
+// JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
+// but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
+// unspecified (HTTP errors and contents of 'error').
+//
+// 1.0 spec: http://json-rpc.org/wiki/specification
+// 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
+// http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
+//
+
+string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
+{
+ Object request;
+ request.push_back(Pair("method", strMethod));
+ request.push_back(Pair("params", params));
+ request.push_back(Pair("id", id));
+ return write_string(Value(request), false) + "\n";
+}
+
+string JSONRPCReply(const Value& result, const Value& error, const Value& id)
+{
+ Object reply;
+ if (error.type() != null_type)
+ reply.push_back(Pair("result", Value::null));
+ else
+ reply.push_back(Pair("result", result));
+ reply.push_back(Pair("error", error));
+ reply.push_back(Pair("id", id));
+ return write_string(Value(reply), false) + "\n";
+}
+
+void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
+{
+ // Send error reply from json-rpc error object
+ int nStatus = 500;
+ int code = find_value(objError, "code").get_int();
+ if (code == -32600) nStatus = 400;
+ else if (code == -32601) nStatus = 404;
+ string strReply = JSONRPCReply(Value::null, objError, id);
+ stream << HTTPReply(nStatus, strReply) << std::flush;
+}
+
+bool ClientAllowed(const string& strAddress)
+{
+ if (strAddress == asio::ip::address_v4::loopback().to_string())
+ return true;
+ const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
+ BOOST_FOREACH(string strAllow, vAllow)
+ if (WildcardMatch(strAddress, strAllow))
+ return true;
+ return false;
+}
+
+#ifdef USE_SSL
+//
+// IOStream device that speaks SSL but can also speak non-SSL
+//
+class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
+public:
+ SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
+ {
+ fUseSSL = fUseSSLIn;
+ fNeedHandshake = fUseSSLIn;
+ }
+
+ void handshake(ssl::stream_base::handshake_type role)
+ {
+ if (!fNeedHandshake) return;
+ fNeedHandshake = false;
+ stream.handshake(role);
+ }
+ std::streamsize read(char* s, std::streamsize n)
+ {
+ handshake(ssl::stream_base::server); // HTTPS servers read first
+ if (fUseSSL) return stream.read_some(asio::buffer(s, n));
+ return stream.next_layer().read_some(asio::buffer(s, n));
+ }
+ std::streamsize write(const char* s, std::streamsize n)
+ {
+ handshake(ssl::stream_base::client); // HTTPS clients write first
+ if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
+ return asio::write(stream.next_layer(), asio::buffer(s, n));
+ }
+ bool connect(const std::string& server, const std::string& port)
+ {
+ ip::tcp::resolver resolver(stream.get_io_service());
+ ip::tcp::resolver::query query(server.c_str(), port.c_str());
+ ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
+ ip::tcp::resolver::iterator end;
+ boost::system::error_code error = asio::error::host_not_found;
+ while (error && endpoint_iterator != end)
+ {
+ stream.lowest_layer().close();
+ stream.lowest_layer().connect(*endpoint_iterator++, error);
+ }
+ if (error)
+ return false;
+ return true;
+ }
+
+private:
+ bool fNeedHandshake;
+ bool fUseSSL;
+ SSLStream& stream;
+};
+#endif
+
+void ThreadRPCServer(void* parg)
+{
+ IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer(parg));
+ try
+ {
+ vnThreadsRunning[4]++;
+ ThreadRPCServer2(parg);
+ vnThreadsRunning[4]--;
+ }
+ catch (std::exception& e) {
+ vnThreadsRunning[4]--;
+ PrintException(&e, "ThreadRPCServer()");
+ } catch (...) {
+ vnThreadsRunning[4]--;
+ PrintException(NULL, "ThreadRPCServer()");
+ }
+ printf("ThreadRPCServer exiting\n");
+}
+
+void ThreadRPCServer2(void* parg)
+{
+ printf("ThreadRPCServer started\n");
+
+ if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
+ {
+ string strWhatAmI = "To use bitcoind";
+ if (mapArgs.count("-server"))
+ strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
+ else if (mapArgs.count("-daemon"))
+ strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
+ PrintConsole(
+ _("Warning: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n"
+ "If the file does not exist, create it with owner-readable-only file permissions.\n"),
+ strWhatAmI.c_str(),
+ GetConfigFile().c_str());
+ CreateThread(Shutdown, NULL);
+ return;
+ }
+
+ bool fUseSSL = GetBoolArg("-rpcssl");
+ asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
+
+ asio::io_service io_service;
+ ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
+ ip::tcp::acceptor acceptor(io_service, endpoint);
+
+ acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
+
+#ifdef USE_SSL
+ ssl::context context(io_service, ssl::context::sslv23);
+ if (fUseSSL)
+ {
+ context.set_options(ssl::context::no_sslv2);
+ filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
+ if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
+ if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
+ else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
+ filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
+ if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
+ if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
+ else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
+
+ string ciphers = GetArg("-rpcsslciphers",
+ "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
+ SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
+ }
+#else
+ if (fUseSSL)
+ throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
+#endif
+
+ loop
+ {
+ // Accept connection
+#ifdef USE_SSL
+ SSLStream sslStream(io_service, context);
+ SSLIOStreamDevice d(sslStream, fUseSSL);
+ iostreams::stream<SSLIOStreamDevice> stream(d);
+#else
+ ip::tcp::iostream stream;
+#endif
+
+ ip::tcp::endpoint peer;
+ vnThreadsRunning[4]--;
+#ifdef USE_SSL
+ acceptor.accept(sslStream.lowest_layer(), peer);
+#else
+ acceptor.accept(*stream.rdbuf(), peer);
+#endif
+ vnThreadsRunning[4]++;
+ if (fShutdown)
+ return;
+
+ // Restrict callers by IP
+ if (!ClientAllowed(peer.address().to_string()))
+ continue;
+
+ map<string, string> mapHeaders;
+ string strRequest;
+
+ boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
+ if (!api_caller.timed_join(boost::posix_time::seconds(GetArg("-rpctimeout", 30))))
+ { // Timed out:
+ acceptor.cancel();
+ printf("ThreadRPCServer ReadHTTP timeout\n");
+ continue;
+ }
+
+ // Check authorization
+ if (mapHeaders.count("authorization") == 0)
+ {
+ stream << HTTPReply(401, "") << std::flush;
+ continue;
+ }
+ if (!HTTPAuthorized(mapHeaders))
+ {
+ // Deter brute-forcing short passwords
+ if (mapArgs["-rpcpassword"].size() < 15)
+ Sleep(50);
+
+ stream << HTTPReply(401, "") << std::flush;
+ printf("ThreadRPCServer incorrect password attempt\n");
+ continue;
+ }
+
+ Value id = Value::null;
+ try
+ {
+ // Parse request
+ Value valRequest;
+ if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
+ throw JSONRPCError(-32700, "Parse error");
+ const Object& request = valRequest.get_obj();
+
+ // Parse id now so errors from here on will have the id
+ id = find_value(request, "id");
+
+ // Parse method
+ Value valMethod = find_value(request, "method");
+ if (valMethod.type() == null_type)
+ throw JSONRPCError(-32600, "Missing method");
+ if (valMethod.type() != str_type)
+ throw JSONRPCError(-32600, "Method must be a string");
+ string strMethod = valMethod.get_str();
+ if (strMethod != "getwork")
+ printf("ThreadRPCServer method=%s\n", strMethod.c_str());
+
+ // Parse params
+ Value valParams = find_value(request, "params");
+ Array params;
+ if (valParams.type() == array_type)
+ params = valParams.get_array();
+ else if (valParams.type() == null_type)
+ params = Array();
+ else
+ throw JSONRPCError(-32600, "Params must be an array");
+
+ // Find method
+ map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
+ if (mi == mapCallTable.end())
+ throw JSONRPCError(-32601, "Method not found");
+
+ // Observe safe mode
+ string strWarning = GetWarnings("rpc");
+ if (strWarning != "" && !GetBoolArg("-disablesafemode") && !setAllowInSafeMode.count(strMethod))
+ throw JSONRPCError(-2, string("Safe mode: ") + strWarning);
+
+ try
+ {
+ // Execute
+ Value result = (*(*mi).second)(params, false);
+
+ // Send reply
+ string strReply = JSONRPCReply(result, Value::null, id);
+ stream << HTTPReply(200, strReply) << std::flush;
+ }
+ catch (std::exception& e)
+ {
+ ErrorReply(stream, JSONRPCError(-1, e.what()), id);
+ }
+ }
+ catch (Object& objError)
+ {
+ ErrorReply(stream, objError, id);
+ }
+ catch (std::exception& e)
+ {
+ ErrorReply(stream, JSONRPCError(-32700, e.what()), id);
+ }
+ }
+}
+
+
+
+
+Object CallRPC(const string& strMethod, const Array& params)
+{
+ if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
+ throw runtime_error(strprintf(
+ _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
+ "If the file does not exist, create it with owner-readable-only file permissions."),
+ GetConfigFile().c_str()));
+
+ // Connect to localhost
+ bool fUseSSL = GetBoolArg("-rpcssl");
+#ifdef USE_SSL
+ asio::io_service io_service;
+ ssl::context context(io_service, ssl::context::sslv23);
+ context.set_options(ssl::context::no_sslv2);
+ SSLStream sslStream(io_service, context);
+ SSLIOStreamDevice d(sslStream, fUseSSL);
+ iostreams::stream<SSLIOStreamDevice> stream(d);
+ if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
+ throw runtime_error("couldn't connect to server");
+#else
+ if (fUseSSL)
+ throw runtime_error("-rpcssl=1, but bitcoin compiled without full openssl libraries.");
+
+ ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
+ if (stream.fail())
+ throw runtime_error("couldn't connect to server");
+#endif
+
+
+ // HTTP basic authentication
+ string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
+ map<string, string> mapRequestHeaders;
+ mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
+
+ // Send request
+ string strRequest = JSONRPCRequest(strMethod, params, 1);
+ string strPost = HTTPPost(strRequest, mapRequestHeaders);
+ stream << strPost << std::flush;
+
+ // Receive reply
+ map<string, string> mapHeaders;
+ string strReply;
+ int nStatus = ReadHTTP(stream, mapHeaders, strReply);
+ if (nStatus == 401)
+ throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
+ else if (nStatus >= 400 && nStatus != 400 && nStatus != 404 && nStatus != 500)
+ throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
+ else if (strReply.empty())
+ throw runtime_error("no response from server");
+
+ // Parse reply
+ Value valReply;
+ if (!read_string(strReply, valReply))
+ throw runtime_error("couldn't parse reply from server");
+ const Object& reply = valReply.get_obj();
+ if (reply.empty())
+ throw runtime_error("expected reply to have result, error and id properties");
+
+ return reply;
+}
+
+
+
+
+template<typename T>
+void ConvertTo(Value& value)
+{
+ if (value.type() == str_type)
+ {
+ // reinterpret string as unquoted json value
+ Value value2;
+ if (!read_string(value.get_str(), value2))
+ throw runtime_error("type mismatch");
+ value = value2.get_value<T>();
+ }
+ else
+ {
+ value = value.get_value<T>();
+ }
+}
+
+int CommandLineRPC(int argc, char *argv[])
+{
+ string strPrint;
+ int nRet = 0;
+ try
+ {
+ // Skip switches
+ while (argc > 1 && IsSwitchChar(argv[1][0]))
+ {
+ argc--;
+ argv++;
+ }
+
+ // Method
+ if (argc < 2)
+ throw runtime_error("too few parameters");
+ string strMethod = argv[1];
+
+ // Parameters default to strings
+ Array params;
+ for (int i = 2; i < argc; i++)
+ params.push_back(argv[i]);
+ int n = params.size();
+
+ //
+ // Special case non-string parameter types
+ //
+ if (strMethod == "setgenerate" && n > 0) ConvertTo<bool>(params[0]);
+ if (strMethod == "setgenerate" && n > 1) ConvertTo<boost::int64_t>(params[1]);
+ if (strMethod == "sendtoaddress" && n > 1) ConvertTo<double>(params[1]);
+ if (strMethod == "settxfee" && n > 0) ConvertTo<double>(params[0]);
+ if (strMethod == "getamountreceived" && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated
+ if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo<boost::int64_t>(params[1]);
+ if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo<boost::int64_t>(params[1]);
+ if (strMethod == "getreceivedbylabel" && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated
+ if (strMethod == "getallreceived" && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated
+ if (strMethod == "getallreceived" && n > 1) ConvertTo<bool>(params[1]);
+ if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo<boost::int64_t>(params[0]);
+ if (strMethod == "listreceivedbyaddress" && n > 1) ConvertTo<bool>(params[1]);
+ if (strMethod == "listreceivedbyaccount" && n > 0) ConvertTo<boost::int64_t>(params[0]);
+ if (strMethod == "listreceivedbyaccount" && n > 1) ConvertTo<bool>(params[1]);
+ if (strMethod == "listreceivedbylabel" && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated
+ if (strMethod == "listreceivedbylabel" && n > 1) ConvertTo<bool>(params[1]); // deprecated
+ if (strMethod == "getbalance" && n > 1) ConvertTo<boost::int64_t>(params[1]);
+ if (strMethod == "move" && n > 2) ConvertTo<double>(params[2]);
+ if (strMethod == "move" && n > 3) ConvertTo<boost::int64_t>(params[3]);
+ if (strMethod == "sendfrom" && n > 2) ConvertTo<double>(params[2]);
+ if (strMethod == "sendfrom" && n > 3) ConvertTo<boost::int64_t>(params[3]);
+ if (strMethod == "listtransactions" && n > 1) ConvertTo<boost::int64_t>(params[1]);
+ if (strMethod == "listtransactions" && n > 2) ConvertTo<boost::int64_t>(params[2]);
+ if (strMethod == "listaccounts" && n > 0) ConvertTo<boost::int64_t>(params[0]);
+ if (strMethod == "sendmany" && n > 1)
+ {
+ string s = params[1].get_str();
+ Value v;
+ if (!read_string(s, v) || v.type() != obj_type)
+ throw runtime_error("type mismatch");
+ params[1] = v.get_obj();
+ }
+ if (strMethod == "sendmany" && n > 2) ConvertTo<boost::int64_t>(params[2]);
+
+ // Execute
+ Object reply = CallRPC(strMethod, params);
+
+ // Parse reply
+ const Value& result = find_value(reply, "result");
+ const Value& error = find_value(reply, "error");
+ const Value& id = find_value(reply, "id");
+
+ if (error.type() != null_type)
+ {
+ // Error
+ strPrint = "error: " + write_string(error, false);
+ int code = find_value(error.get_obj(), "code").get_int();
+ nRet = abs(code);
+ }
+ else
+ {
+ // Result
+ if (result.type() == null_type)
+ strPrint = "";
+ else if (result.type() == str_type)
+ strPrint = result.get_str();
+ else
+ strPrint = write_string(result, true);
+ }
+ }
+ catch (std::exception& e)
+ {
+ strPrint = string("error: ") + e.what();
+ nRet = 87;
+ }
+ catch (...)
+ {
+ PrintException(NULL, "CommandLineRPC()");
+ }
+
+ if (strPrint != "")
+ {
+#if defined(__WXMSW__) && defined(GUI)
+ // Windows GUI apps can't print to command line,
+ // so settle for a message box yuck
+ MyMessageBox(strPrint, "Bitcoin", wxOK);
+#else
+ fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
+#endif
+ }
+ return nRet;
+}
+
+
+
+
+#ifdef TEST
+int main(int argc, char *argv[])
+{
+#ifdef _MSC_VER
+ // Turn off microsoft heap dump noise
+ _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
+ _CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
+#endif
+ setbuf(stdin, NULL);
+ setbuf(stdout, NULL);
+ setbuf(stderr, NULL);
+
+ try
+ {
+ if (argc >= 2 && string(argv[1]) == "-server")
+ {
+ printf("server ready\n");
+ ThreadRPCServer(NULL);
+ }
+ else
+ {
+ return CommandLineRPC(argc, argv);
+ }
+ }
+ catch (std::exception& e) {
+ PrintException(&e, "main()");
+ } catch (...) {
+ PrintException(NULL, "main()");
+ }
+ return 0;
+}
+#endif
diff --git a/core/src/script.cpp b/core/src/script.cpp
new file mode 100644
index 0000000000..97334ca0a0
--- /dev/null
+++ b/core/src/script.cpp
@@ -0,0 +1,1208 @@
+// 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.
+#include "headers.h"
+
+using namespace std;
+using namespace boost;
+
+bool CheckSig(vector<unsigned char> vchSig, vector<unsigned char> vchPubKey, CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
+
+
+
+typedef vector<unsigned char> valtype;
+static const valtype vchFalse(0);
+static const valtype vchZero(0);
+static const valtype vchTrue(1, 1);
+static const CBigNum bnZero(0);
+static const CBigNum bnOne(1);
+static const CBigNum bnFalse(0);
+static const CBigNum bnTrue(1);
+static const size_t nMaxNumSize = 4;
+
+
+CBigNum CastToBigNum(const valtype& vch)
+{
+ if (vch.size() > nMaxNumSize)
+ throw runtime_error("CastToBigNum() : overflow");
+ // Get rid of extra leading zeros
+ return CBigNum(CBigNum(vch).getvch());
+}
+
+bool CastToBool(const valtype& vch)
+{
+ for (int i = 0; i < vch.size(); i++)
+ {
+ if (vch[i] != 0)
+ {
+ // Can be negative zero
+ if (i == vch.size()-1 && vch[i] == 0x80)
+ return false;
+ return true;
+ }
+ }
+ return false;
+}
+
+void MakeSameSize(valtype& vch1, valtype& vch2)
+{
+ // Lengthen the shorter one
+ if (vch1.size() < vch2.size())
+ vch1.resize(vch2.size(), 0);
+ if (vch2.size() < vch1.size())
+ vch2.resize(vch1.size(), 0);
+}
+
+
+
+//
+// Script is a stack machine (like Forth) that evaluates a predicate
+// returning a bool indicating valid or not. There are no loops.
+//
+#define stacktop(i) (stack.at(stack.size()+(i)))
+#define altstacktop(i) (altstack.at(altstack.size()+(i)))
+static inline void popstack(vector<valtype>& stack)
+{
+ if (stack.empty())
+ throw runtime_error("popstack() : stack empty");
+ stack.pop_back();
+}
+
+
+bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, int nHashType)
+{
+ CAutoBN_CTX pctx;
+ CScript::const_iterator pc = script.begin();
+ CScript::const_iterator pend = script.end();
+ CScript::const_iterator pbegincodehash = script.begin();
+ opcodetype opcode;
+ valtype vchPushValue;
+ vector<bool> vfExec;
+ vector<valtype> altstack;
+ if (script.size() > 10000)
+ return false;
+ int nOpCount = 0;
+
+
+ try
+ {
+ while (pc < pend)
+ {
+ bool fExec = !count(vfExec.begin(), vfExec.end(), false);
+
+ //
+ // Read instruction
+ //
+ if (!script.GetOp(pc, opcode, vchPushValue))
+ return false;
+ if (vchPushValue.size() > 520)
+ return false;
+ if (opcode > OP_16 && ++nOpCount > 201)
+ return false;
+
+ if (opcode == OP_CAT ||
+ opcode == OP_SUBSTR ||
+ opcode == OP_LEFT ||
+ opcode == OP_RIGHT ||
+ opcode == OP_INVERT ||
+ opcode == OP_AND ||
+ opcode == OP_OR ||
+ opcode == OP_XOR ||
+ opcode == OP_2MUL ||
+ opcode == OP_2DIV ||
+ opcode == OP_MUL ||
+ opcode == OP_DIV ||
+ opcode == OP_MOD ||
+ opcode == OP_LSHIFT ||
+ opcode == OP_RSHIFT)
+ return false;
+
+ if (fExec && 0 <= opcode && opcode <= OP_PUSHDATA4)
+ stack.push_back(vchPushValue);
+ else if (fExec || (OP_IF <= opcode && opcode <= OP_ENDIF))
+ switch (opcode)
+ {
+ //
+ // Push value
+ //
+ case OP_1NEGATE:
+ case OP_1:
+ case OP_2:
+ case OP_3:
+ case OP_4:
+ case OP_5:
+ case OP_6:
+ case OP_7:
+ case OP_8:
+ case OP_9:
+ case OP_10:
+ case OP_11:
+ case OP_12:
+ case OP_13:
+ case OP_14:
+ case OP_15:
+ case OP_16:
+ {
+ // ( -- value)
+ CBigNum bn((int)opcode - (int)(OP_1 - 1));
+ stack.push_back(bn.getvch());
+ }
+ break;
+
+
+ //
+ // Control
+ //
+ case OP_NOP:
+ case OP_NOP1: case OP_NOP2: case OP_NOP3: case OP_NOP4: case OP_NOP5:
+ case OP_NOP6: case OP_NOP7: case OP_NOP8: case OP_NOP9: case OP_NOP10:
+ break;
+
+ case OP_IF:
+ case OP_NOTIF:
+ {
+ // <expression> if [statements] [else [statements]] endif
+ bool fValue = false;
+ if (fExec)
+ {
+ if (stack.size() < 1)
+ return false;
+ valtype& vch = stacktop(-1);
+ fValue = CastToBool(vch);
+ if (opcode == OP_NOTIF)
+ fValue = !fValue;
+ popstack(stack);
+ }
+ vfExec.push_back(fValue);
+ }
+ break;
+
+ case OP_ELSE:
+ {
+ if (vfExec.empty())
+ return false;
+ vfExec.back() = !vfExec.back();
+ }
+ break;
+
+ case OP_ENDIF:
+ {
+ if (vfExec.empty())
+ return false;
+ vfExec.pop_back();
+ }
+ break;
+
+ case OP_VERIFY:
+ {
+ // (true -- ) or
+ // (false -- false) and return
+ if (stack.size() < 1)
+ return false;
+ bool fValue = CastToBool(stacktop(-1));
+ if (fValue)
+ popstack(stack);
+ else
+ return false;
+ }
+ break;
+
+ case OP_RETURN:
+ {
+ return false;
+ }
+ break;
+
+
+ //
+ // Stack ops
+ //
+ case OP_TOALTSTACK:
+ {
+ if (stack.size() < 1)
+ return false;
+ altstack.push_back(stacktop(-1));
+ popstack(stack);
+ }
+ break;
+
+ case OP_FROMALTSTACK:
+ {
+ if (altstack.size() < 1)
+ return false;
+ stack.push_back(altstacktop(-1));
+ popstack(altstack);
+ }
+ break;
+
+ case OP_2DROP:
+ {
+ // (x1 x2 -- )
+ if (stack.size() < 2)
+ return false;
+ popstack(stack);
+ popstack(stack);
+ }
+ break;
+
+ case OP_2DUP:
+ {
+ // (x1 x2 -- x1 x2 x1 x2)
+ if (stack.size() < 2)
+ return false;
+ valtype vch1 = stacktop(-2);
+ valtype vch2 = stacktop(-1);
+ stack.push_back(vch1);
+ stack.push_back(vch2);
+ }
+ break;
+
+ case OP_3DUP:
+ {
+ // (x1 x2 x3 -- x1 x2 x3 x1 x2 x3)
+ if (stack.size() < 3)
+ return false;
+ valtype vch1 = stacktop(-3);
+ valtype vch2 = stacktop(-2);
+ valtype vch3 = stacktop(-1);
+ stack.push_back(vch1);
+ stack.push_back(vch2);
+ stack.push_back(vch3);
+ }
+ break;
+
+ case OP_2OVER:
+ {
+ // (x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2)
+ if (stack.size() < 4)
+ return false;
+ valtype vch1 = stacktop(-4);
+ valtype vch2 = stacktop(-3);
+ stack.push_back(vch1);
+ stack.push_back(vch2);
+ }
+ break;
+
+ case OP_2ROT:
+ {
+ // (x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2)
+ if (stack.size() < 6)
+ return false;
+ valtype vch1 = stacktop(-6);
+ valtype vch2 = stacktop(-5);
+ stack.erase(stack.end()-6, stack.end()-4);
+ stack.push_back(vch1);
+ stack.push_back(vch2);
+ }
+ break;
+
+ case OP_2SWAP:
+ {
+ // (x1 x2 x3 x4 -- x3 x4 x1 x2)
+ if (stack.size() < 4)
+ return false;
+ swap(stacktop(-4), stacktop(-2));
+ swap(stacktop(-3), stacktop(-1));
+ }
+ break;
+
+ case OP_IFDUP:
+ {
+ // (x - 0 | x x)
+ if (stack.size() < 1)
+ return false;
+ valtype vch = stacktop(-1);
+ if (CastToBool(vch))
+ stack.push_back(vch);
+ }
+ break;
+
+ case OP_DEPTH:
+ {
+ // -- stacksize
+ CBigNum bn(stack.size());
+ stack.push_back(bn.getvch());
+ }
+ break;
+
+ case OP_DROP:
+ {
+ // (x -- )
+ if (stack.size() < 1)
+ return false;
+ popstack(stack);
+ }
+ break;
+
+ case OP_DUP:
+ {
+ // (x -- x x)
+ if (stack.size() < 1)
+ return false;
+ valtype vch = stacktop(-1);
+ stack.push_back(vch);
+ }
+ break;
+
+ case OP_NIP:
+ {
+ // (x1 x2 -- x2)
+ if (stack.size() < 2)
+ return false;
+ stack.erase(stack.end() - 2);
+ }
+ break;
+
+ case OP_OVER:
+ {
+ // (x1 x2 -- x1 x2 x1)
+ if (stack.size() < 2)
+ return false;
+ valtype vch = stacktop(-2);
+ stack.push_back(vch);
+ }
+ break;
+
+ case OP_PICK:
+ case OP_ROLL:
+ {
+ // (xn ... x2 x1 x0 n - xn ... x2 x1 x0 xn)
+ // (xn ... x2 x1 x0 n - ... x2 x1 x0 xn)
+ if (stack.size() < 2)
+ return false;
+ int n = CastToBigNum(stacktop(-1)).getint();
+ popstack(stack);
+ if (n < 0 || n >= stack.size())
+ return false;
+ valtype vch = stacktop(-n-1);
+ if (opcode == OP_ROLL)
+ stack.erase(stack.end()-n-1);
+ stack.push_back(vch);
+ }
+ break;
+
+ case OP_ROT:
+ {
+ // (x1 x2 x3 -- x2 x3 x1)
+ // x2 x1 x3 after first swap
+ // x2 x3 x1 after second swap
+ if (stack.size() < 3)
+ return false;
+ swap(stacktop(-3), stacktop(-2));
+ swap(stacktop(-2), stacktop(-1));
+ }
+ break;
+
+ case OP_SWAP:
+ {
+ // (x1 x2 -- x2 x1)
+ if (stack.size() < 2)
+ return false;
+ swap(stacktop(-2), stacktop(-1));
+ }
+ break;
+
+ case OP_TUCK:
+ {
+ // (x1 x2 -- x2 x1 x2)
+ if (stack.size() < 2)
+ return false;
+ valtype vch = stacktop(-1);
+ stack.insert(stack.end()-2, vch);
+ }
+ break;
+
+
+ //
+ // Splice ops
+ //
+ case OP_CAT:
+ {
+ // (x1 x2 -- out)
+ if (stack.size() < 2)
+ return false;
+ valtype& vch1 = stacktop(-2);
+ valtype& vch2 = stacktop(-1);
+ vch1.insert(vch1.end(), vch2.begin(), vch2.end());
+ popstack(stack);
+ if (stacktop(-1).size() > 520)
+ return false;
+ }
+ break;
+
+ case OP_SUBSTR:
+ {
+ // (in begin size -- out)
+ if (stack.size() < 3)
+ return false;
+ valtype& vch = stacktop(-3);
+ int nBegin = CastToBigNum(stacktop(-2)).getint();
+ int nEnd = nBegin + CastToBigNum(stacktop(-1)).getint();
+ if (nBegin < 0 || nEnd < nBegin)
+ return false;
+ if (nBegin > vch.size())
+ nBegin = vch.size();
+ if (nEnd > vch.size())
+ nEnd = vch.size();
+ vch.erase(vch.begin() + nEnd, vch.end());
+ vch.erase(vch.begin(), vch.begin() + nBegin);
+ popstack(stack);
+ popstack(stack);
+ }
+ break;
+
+ case OP_LEFT:
+ case OP_RIGHT:
+ {
+ // (in size -- out)
+ if (stack.size() < 2)
+ return false;
+ valtype& vch = stacktop(-2);
+ int nSize = CastToBigNum(stacktop(-1)).getint();
+ if (nSize < 0)
+ return false;
+ if (nSize > vch.size())
+ nSize = vch.size();
+ if (opcode == OP_LEFT)
+ vch.erase(vch.begin() + nSize, vch.end());
+ else
+ vch.erase(vch.begin(), vch.end() - nSize);
+ popstack(stack);
+ }
+ break;
+
+ case OP_SIZE:
+ {
+ // (in -- in size)
+ if (stack.size() < 1)
+ return false;
+ CBigNum bn(stacktop(-1).size());
+ stack.push_back(bn.getvch());
+ }
+ break;
+
+
+ //
+ // Bitwise logic
+ //
+ case OP_INVERT:
+ {
+ // (in - out)
+ if (stack.size() < 1)
+ return false;
+ valtype& vch = stacktop(-1);
+ for (int i = 0; i < vch.size(); i++)
+ vch[i] = ~vch[i];
+ }
+ break;
+
+ case OP_AND:
+ case OP_OR:
+ case OP_XOR:
+ {
+ // (x1 x2 - out)
+ if (stack.size() < 2)
+ return false;
+ valtype& vch1 = stacktop(-2);
+ valtype& vch2 = stacktop(-1);
+ MakeSameSize(vch1, vch2);
+ if (opcode == OP_AND)
+ {
+ for (int i = 0; i < vch1.size(); i++)
+ vch1[i] &= vch2[i];
+ }
+ else if (opcode == OP_OR)
+ {
+ for (int i = 0; i < vch1.size(); i++)
+ vch1[i] |= vch2[i];
+ }
+ else if (opcode == OP_XOR)
+ {
+ for (int i = 0; i < vch1.size(); i++)
+ vch1[i] ^= vch2[i];
+ }
+ popstack(stack);
+ }
+ break;
+
+ case OP_EQUAL:
+ case OP_EQUALVERIFY:
+ //case OP_NOTEQUAL: // use OP_NUMNOTEQUAL
+ {
+ // (x1 x2 - bool)
+ if (stack.size() < 2)
+ return false;
+ valtype& vch1 = stacktop(-2);
+ valtype& vch2 = stacktop(-1);
+ bool fEqual = (vch1 == vch2);
+ // OP_NOTEQUAL is disabled because it would be too easy to say
+ // something like n != 1 and have some wiseguy pass in 1 with extra
+ // zero bytes after it (numerically, 0x01 == 0x0001 == 0x000001)
+ //if (opcode == OP_NOTEQUAL)
+ // fEqual = !fEqual;
+ popstack(stack);
+ popstack(stack);
+ stack.push_back(fEqual ? vchTrue : vchFalse);
+ if (opcode == OP_EQUALVERIFY)
+ {
+ if (fEqual)
+ popstack(stack);
+ else
+ return false;
+ }
+ }
+ break;
+
+
+ //
+ // Numeric
+ //
+ case OP_1ADD:
+ case OP_1SUB:
+ case OP_2MUL:
+ case OP_2DIV:
+ case OP_NEGATE:
+ case OP_ABS:
+ case OP_NOT:
+ case OP_0NOTEQUAL:
+ {
+ // (in -- out)
+ if (stack.size() < 1)
+ return false;
+ CBigNum bn = CastToBigNum(stacktop(-1));
+ switch (opcode)
+ {
+ case OP_1ADD: bn += bnOne; break;
+ case OP_1SUB: bn -= bnOne; break;
+ case OP_2MUL: bn <<= 1; break;
+ case OP_2DIV: bn >>= 1; break;
+ case OP_NEGATE: bn = -bn; break;
+ case OP_ABS: if (bn < bnZero) bn = -bn; break;
+ case OP_NOT: bn = (bn == bnZero); break;
+ case OP_0NOTEQUAL: bn = (bn != bnZero); break;
+ }
+ popstack(stack);
+ stack.push_back(bn.getvch());
+ }
+ break;
+
+ case OP_ADD:
+ case OP_SUB:
+ case OP_MUL:
+ case OP_DIV:
+ case OP_MOD:
+ case OP_LSHIFT:
+ case OP_RSHIFT:
+ case OP_BOOLAND:
+ case OP_BOOLOR:
+ case OP_NUMEQUAL:
+ case OP_NUMEQUALVERIFY:
+ case OP_NUMNOTEQUAL:
+ case OP_LESSTHAN:
+ case OP_GREATERTHAN:
+ case OP_LESSTHANOREQUAL:
+ case OP_GREATERTHANOREQUAL:
+ case OP_MIN:
+ case OP_MAX:
+ {
+ // (x1 x2 -- out)
+ if (stack.size() < 2)
+ return false;
+ CBigNum bn1 = CastToBigNum(stacktop(-2));
+ CBigNum bn2 = CastToBigNum(stacktop(-1));
+ CBigNum bn;
+ switch (opcode)
+ {
+ case OP_ADD:
+ bn = bn1 + bn2;
+ break;
+
+ case OP_SUB:
+ bn = bn1 - bn2;
+ break;
+
+ case OP_MUL:
+ if (!BN_mul(&bn, &bn1, &bn2, pctx))
+ return false;
+ break;
+
+ case OP_DIV:
+ if (!BN_div(&bn, NULL, &bn1, &bn2, pctx))
+ return false;
+ break;
+
+ case OP_MOD:
+ if (!BN_mod(&bn, &bn1, &bn2, pctx))
+ return false;
+ break;
+
+ case OP_LSHIFT:
+ if (bn2 < bnZero || bn2 > CBigNum(2048))
+ return false;
+ bn = bn1 << bn2.getulong();
+ break;
+
+ case OP_RSHIFT:
+ if (bn2 < bnZero || bn2 > CBigNum(2048))
+ return false;
+ bn = bn1 >> bn2.getulong();
+ break;
+
+ case OP_BOOLAND: bn = (bn1 != bnZero && bn2 != bnZero); break;
+ case OP_BOOLOR: bn = (bn1 != bnZero || bn2 != bnZero); break;
+ case OP_NUMEQUAL: bn = (bn1 == bn2); break;
+ case OP_NUMEQUALVERIFY: bn = (bn1 == bn2); break;
+ case OP_NUMNOTEQUAL: bn = (bn1 != bn2); break;
+ case OP_LESSTHAN: bn = (bn1 < bn2); break;
+ case OP_GREATERTHAN: bn = (bn1 > bn2); break;
+ case OP_LESSTHANOREQUAL: bn = (bn1 <= bn2); break;
+ case OP_GREATERTHANOREQUAL: bn = (bn1 >= bn2); break;
+ case OP_MIN: bn = (bn1 < bn2 ? bn1 : bn2); break;
+ case OP_MAX: bn = (bn1 > bn2 ? bn1 : bn2); break;
+ }
+ popstack(stack);
+ popstack(stack);
+ stack.push_back(bn.getvch());
+
+ if (opcode == OP_NUMEQUALVERIFY)
+ {
+ if (CastToBool(stacktop(-1)))
+ popstack(stack);
+ else
+ return false;
+ }
+ }
+ break;
+
+ case OP_WITHIN:
+ {
+ // (x min max -- out)
+ if (stack.size() < 3)
+ return false;
+ CBigNum bn1 = CastToBigNum(stacktop(-3));
+ CBigNum bn2 = CastToBigNum(stacktop(-2));
+ CBigNum bn3 = CastToBigNum(stacktop(-1));
+ bool fValue = (bn2 <= bn1 && bn1 < bn3);
+ popstack(stack);
+ popstack(stack);
+ popstack(stack);
+ stack.push_back(fValue ? vchTrue : vchFalse);
+ }
+ break;
+
+
+ //
+ // Crypto
+ //
+ case OP_RIPEMD160:
+ case OP_SHA1:
+ case OP_SHA256:
+ case OP_HASH160:
+ case OP_HASH256:
+ {
+ // (in -- hash)
+ if (stack.size() < 1)
+ return false;
+ valtype& vch = stacktop(-1);
+ valtype vchHash((opcode == OP_RIPEMD160 || opcode == OP_SHA1 || opcode == OP_HASH160) ? 20 : 32);
+ if (opcode == OP_RIPEMD160)
+ RIPEMD160(&vch[0], vch.size(), &vchHash[0]);
+ else if (opcode == OP_SHA1)
+ SHA1(&vch[0], vch.size(), &vchHash[0]);
+ else if (opcode == OP_SHA256)
+ SHA256(&vch[0], vch.size(), &vchHash[0]);
+ else if (opcode == OP_HASH160)
+ {
+ uint160 hash160 = Hash160(vch);
+ memcpy(&vchHash[0], &hash160, sizeof(hash160));
+ }
+ else if (opcode == OP_HASH256)
+ {
+ uint256 hash = Hash(vch.begin(), vch.end());
+ memcpy(&vchHash[0], &hash, sizeof(hash));
+ }
+ popstack(stack);
+ stack.push_back(vchHash);
+ }
+ break;
+
+ case OP_CODESEPARATOR:
+ {
+ // Hash starts after the code separator
+ pbegincodehash = pc;
+ }
+ break;
+
+ case OP_CHECKSIG:
+ case OP_CHECKSIGVERIFY:
+ {
+ // (sig pubkey -- bool)
+ if (stack.size() < 2)
+ return false;
+
+ valtype& vchSig = stacktop(-2);
+ valtype& vchPubKey = stacktop(-1);
+
+ ////// debug print
+ //PrintHex(vchSig.begin(), vchSig.end(), "sig: %s\n");
+ //PrintHex(vchPubKey.begin(), vchPubKey.end(), "pubkey: %s\n");
+
+ // Subset of script starting at the most recent codeseparator
+ CScript scriptCode(pbegincodehash, pend);
+
+ // Drop the signature, since there's no way for a signature to sign itself
+ scriptCode.FindAndDelete(CScript(vchSig));
+
+ bool fSuccess = CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType);
+
+ popstack(stack);
+ popstack(stack);
+ stack.push_back(fSuccess ? vchTrue : vchFalse);
+ if (opcode == OP_CHECKSIGVERIFY)
+ {
+ if (fSuccess)
+ popstack(stack);
+ else
+ return false;
+ }
+ }
+ break;
+
+ case OP_CHECKMULTISIG:
+ case OP_CHECKMULTISIGVERIFY:
+ {
+ // ([sig ...] num_of_signatures [pubkey ...] num_of_pubkeys -- bool)
+
+ int i = 1;
+ if (stack.size() < i)
+ return false;
+
+ int nKeysCount = CastToBigNum(stacktop(-i)).getint();
+ if (nKeysCount < 0 || nKeysCount > 20)
+ return false;
+ nOpCount += nKeysCount;
+ if (nOpCount > 201)
+ return false;
+ int ikey = ++i;
+ i += nKeysCount;
+ if (stack.size() < i)
+ return false;
+
+ int nSigsCount = CastToBigNum(stacktop(-i)).getint();
+ if (nSigsCount < 0 || nSigsCount > nKeysCount)
+ return false;
+ int isig = ++i;
+ i += nSigsCount;
+ if (stack.size() < i)
+ return false;
+
+ // Subset of script starting at the most recent codeseparator
+ CScript scriptCode(pbegincodehash, pend);
+
+ // Drop the signatures, since there's no way for a signature to sign itself
+ for (int k = 0; k < nSigsCount; k++)
+ {
+ valtype& vchSig = stacktop(-isig-k);
+ scriptCode.FindAndDelete(CScript(vchSig));
+ }
+
+ bool fSuccess = true;
+ while (fSuccess && nSigsCount > 0)
+ {
+ valtype& vchSig = stacktop(-isig);
+ valtype& vchPubKey = stacktop(-ikey);
+
+ // Check signature
+ if (CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType))
+ {
+ isig++;
+ nSigsCount--;
+ }
+ ikey++;
+ nKeysCount--;
+
+ // If there are more signatures left than keys left,
+ // then too many signatures have failed
+ if (nSigsCount > nKeysCount)
+ fSuccess = false;
+ }
+
+ while (i-- > 0)
+ popstack(stack);
+ stack.push_back(fSuccess ? vchTrue : vchFalse);
+
+ if (opcode == OP_CHECKMULTISIGVERIFY)
+ {
+ if (fSuccess)
+ popstack(stack);
+ else
+ return false;
+ }
+ }
+ break;
+
+ default:
+ return false;
+ }
+
+ // Size limits
+ if (stack.size() + altstack.size() > 1000)
+ return false;
+ }
+ }
+ catch (...)
+ {
+ return false;
+ }
+
+
+ if (!vfExec.empty())
+ return false;
+
+ return true;
+}
+
+
+
+
+
+
+
+
+
+uint256 SignatureHash(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType)
+{
+ if (nIn >= txTo.vin.size())
+ {
+ printf("ERROR: SignatureHash() : nIn=%d out of range\n", nIn);
+ return 1;
+ }
+ CTransaction txTmp(txTo);
+
+ // In case concatenating two scripts ends up with two codeseparators,
+ // or an extra one at the end, this prevents all those possible incompatibilities.
+ scriptCode.FindAndDelete(CScript(OP_CODESEPARATOR));
+
+ // Blank out other inputs' signatures
+ for (int i = 0; i < txTmp.vin.size(); i++)
+ txTmp.vin[i].scriptSig = CScript();
+ txTmp.vin[nIn].scriptSig = scriptCode;
+
+ // Blank out some of the outputs
+ if ((nHashType & 0x1f) == SIGHASH_NONE)
+ {
+ // Wildcard payee
+ txTmp.vout.clear();
+
+ // Let the others update at will
+ for (int i = 0; i < txTmp.vin.size(); i++)
+ if (i != nIn)
+ txTmp.vin[i].nSequence = 0;
+ }
+ else if ((nHashType & 0x1f) == SIGHASH_SINGLE)
+ {
+ // Only lockin the txout payee at same index as txin
+ unsigned int nOut = nIn;
+ if (nOut >= txTmp.vout.size())
+ {
+ printf("ERROR: SignatureHash() : nOut=%d out of range\n", nOut);
+ return 1;
+ }
+ txTmp.vout.resize(nOut+1);
+ for (int i = 0; i < nOut; i++)
+ txTmp.vout[i].SetNull();
+
+ // Let the others update at will
+ for (int i = 0; i < txTmp.vin.size(); i++)
+ if (i != nIn)
+ txTmp.vin[i].nSequence = 0;
+ }
+
+ // Blank out other inputs completely, not recommended for open transactions
+ if (nHashType & SIGHASH_ANYONECANPAY)
+ {
+ txTmp.vin[0] = txTmp.vin[nIn];
+ txTmp.vin.resize(1);
+ }
+
+ // Serialize and hash
+ CDataStream ss(SER_GETHASH);
+ ss.reserve(10000);
+ ss << txTmp << nHashType;
+ return Hash(ss.begin(), ss.end());
+}
+
+
+bool CheckSig(vector<unsigned char> vchSig, vector<unsigned char> vchPubKey, CScript scriptCode,
+ const CTransaction& txTo, unsigned int nIn, int nHashType)
+{
+ CKey key;
+ if (!key.SetPubKey(vchPubKey))
+ return false;
+
+ // Hash type is one byte tacked on to the end of the signature
+ if (vchSig.empty())
+ return false;
+ if (nHashType == 0)
+ nHashType = vchSig.back();
+ else if (nHashType != vchSig.back())
+ return false;
+ vchSig.pop_back();
+
+ return key.Verify(SignatureHash(scriptCode, txTo, nIn, nHashType), vchSig);
+}
+
+
+
+
+
+
+
+
+
+
+bool Solver(const CScript& scriptPubKey, vector<pair<opcodetype, valtype> >& vSolutionRet)
+{
+ // Templates
+ static vector<CScript> vTemplates;
+ if (vTemplates.empty())
+ {
+ // Standard tx, sender provides pubkey, receiver adds signature
+ vTemplates.push_back(CScript() << OP_PUBKEY << OP_CHECKSIG);
+
+ // Bitcoin address tx, sender provides hash of pubkey, receiver provides signature and pubkey
+ vTemplates.push_back(CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG);
+ }
+
+ // Scan templates
+ const CScript& script1 = scriptPubKey;
+ BOOST_FOREACH(const CScript& script2, vTemplates)
+ {
+ vSolutionRet.clear();
+ opcodetype opcode1, opcode2;
+ vector<unsigned char> vch1, vch2;
+
+ // Compare
+ CScript::const_iterator pc1 = script1.begin();
+ CScript::const_iterator pc2 = script2.begin();
+ loop
+ {
+ if (pc1 == script1.end() && pc2 == script2.end())
+ {
+ // Found a match
+ reverse(vSolutionRet.begin(), vSolutionRet.end());
+ return true;
+ }
+ if (!script1.GetOp(pc1, opcode1, vch1))
+ break;
+ if (!script2.GetOp(pc2, opcode2, vch2))
+ break;
+ if (opcode2 == OP_PUBKEY)
+ {
+ if (vch1.size() < 33 || vch1.size() > 120)
+ break;
+ vSolutionRet.push_back(make_pair(opcode2, vch1));
+ }
+ else if (opcode2 == OP_PUBKEYHASH)
+ {
+ if (vch1.size() != sizeof(uint160))
+ break;
+ vSolutionRet.push_back(make_pair(opcode2, vch1));
+ }
+ else if (opcode1 != opcode2 || vch1 != vch2)
+ {
+ break;
+ }
+ }
+ }
+
+ vSolutionRet.clear();
+ return false;
+}
+
+
+bool Solver(const CScript& scriptPubKey, uint256 hash, int nHashType, CScript& scriptSigRet)
+{
+ scriptSigRet.clear();
+
+ vector<pair<opcodetype, valtype> > vSolution;
+ if (!Solver(scriptPubKey, vSolution))
+ return false;
+
+ // Compile solution
+ CRITICAL_BLOCK(cs_mapKeys)
+ {
+ BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution)
+ {
+ if (item.first == OP_PUBKEY)
+ {
+ // Sign
+ const valtype& vchPubKey = item.second;
+ if (!mapKeys.count(vchPubKey))
+ return false;
+ if (hash != 0)
+ {
+ vector<unsigned char> vchSig;
+ if (!CKey::Sign(mapKeys[vchPubKey], hash, vchSig))
+ return false;
+ vchSig.push_back((unsigned char)nHashType);
+ scriptSigRet << vchSig;
+ }
+ }
+ else if (item.first == OP_PUBKEYHASH)
+ {
+ // Sign and give pubkey
+ map<uint160, valtype>::iterator mi = mapPubKeys.find(uint160(item.second));
+ if (mi == mapPubKeys.end())
+ return false;
+ const vector<unsigned char>& vchPubKey = (*mi).second;
+ if (!mapKeys.count(vchPubKey))
+ return false;
+ if (hash != 0)
+ {
+ vector<unsigned char> vchSig;
+ if (!CKey::Sign(mapKeys[vchPubKey], hash, vchSig))
+ return false;
+ vchSig.push_back((unsigned char)nHashType);
+ scriptSigRet << vchSig << vchPubKey;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+
+bool IsStandard(const CScript& scriptPubKey)
+{
+ vector<pair<opcodetype, valtype> > vSolution;
+ return Solver(scriptPubKey, vSolution);
+}
+
+
+bool IsMine(const CScript& scriptPubKey)
+{
+ CScript scriptSig;
+ return Solver(scriptPubKey, 0, 0, scriptSig);
+}
+
+
+bool ExtractPubKey(const CScript& scriptPubKey, bool fMineOnly, vector<unsigned char>& vchPubKeyRet)
+{
+ vchPubKeyRet.clear();
+
+ vector<pair<opcodetype, valtype> > vSolution;
+ if (!Solver(scriptPubKey, vSolution))
+ return false;
+
+ CRITICAL_BLOCK(cs_mapKeys)
+ {
+ BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution)
+ {
+ valtype vchPubKey;
+ if (item.first == OP_PUBKEY)
+ {
+ vchPubKey = item.second;
+ }
+ else if (item.first == OP_PUBKEYHASH)
+ {
+ map<uint160, valtype>::iterator mi = mapPubKeys.find(uint160(item.second));
+ if (mi == mapPubKeys.end())
+ continue;
+ vchPubKey = (*mi).second;
+ }
+ if (!fMineOnly || mapKeys.count(vchPubKey))
+ {
+ vchPubKeyRet = vchPubKey;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+
+bool ExtractHash160(const CScript& scriptPubKey, uint160& hash160Ret)
+{
+ hash160Ret = 0;
+
+ vector<pair<opcodetype, valtype> > vSolution;
+ if (!Solver(scriptPubKey, vSolution))
+ return false;
+
+ BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution)
+ {
+ if (item.first == OP_PUBKEYHASH)
+ {
+ hash160Ret = uint160(item.second);
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, int nHashType)
+{
+ vector<vector<unsigned char> > stack;
+ if (!EvalScript(stack, scriptSig, txTo, nIn, nHashType))
+ return false;
+ if (!EvalScript(stack, scriptPubKey, txTo, nIn, nHashType))
+ return false;
+ if (stack.empty())
+ return false;
+ return CastToBool(stack.back());
+}
+
+
+bool SignSignature(const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType, CScript scriptPrereq)
+{
+ assert(nIn < txTo.vin.size());
+ CTxIn& txin = txTo.vin[nIn];
+ assert(txin.prevout.n < txFrom.vout.size());
+ const CTxOut& txout = txFrom.vout[txin.prevout.n];
+
+ // Leave out the signature from the hash, since a signature can't sign itself.
+ // The checksig op will also drop the signatures from its hash.
+ uint256 hash = SignatureHash(scriptPrereq + txout.scriptPubKey, txTo, nIn, nHashType);
+
+ if (!Solver(txout.scriptPubKey, hash, nHashType, txin.scriptSig))
+ return false;
+
+ txin.scriptSig = scriptPrereq + txin.scriptSig;
+
+ // Test solution
+ if (scriptPrereq.empty())
+ if (!VerifyScript(txin.scriptSig, txout.scriptPubKey, txTo, nIn, 0))
+ return false;
+
+ return true;
+}
+
+
+bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsigned int nIn, int nHashType)
+{
+ assert(nIn < txTo.vin.size());
+ const CTxIn& txin = txTo.vin[nIn];
+ if (txin.prevout.n >= txFrom.vout.size())
+ return false;
+ const CTxOut& txout = txFrom.vout[txin.prevout.n];
+
+ if (txin.prevout.hash != txFrom.GetHash())
+ return false;
+
+ if (!VerifyScript(txin.scriptSig, txout.scriptPubKey, txTo, nIn, nHashType))
+ return false;
+
+ // Anytime a signature is successfully verified, it's proof the outpoint is spent,
+ // so lets update the wallet spent flag if it doesn't know due to wallet.dat being
+ // restored from backup or the user making copies of wallet.dat.
+ WalletUpdateSpent(txin.prevout);
+
+ return true;
+}
diff --git a/core/src/util.cpp b/core/src/util.cpp
index 0e88e2eaf7..4e93f625de 100644
--- a/core/src/util.cpp
+++ b/core/src/util.cpp
@@ -1,21 +1,10 @@
// 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>
+#include "headers.h"
using namespace std;
+using namespace boost;
map<string, string> mapArgs;
map<string, vector<string> > mapMultiArgs;
@@ -716,7 +705,7 @@ void GetDataDir(char* pszDir)
if (!pfMkdir[nVariation])
{
pfMkdir[nVariation] = true;
- filesystem::create_directory(pszDir);
+ boost::filesystem::create_directory(pszDir);
}
}
@@ -867,7 +856,7 @@ void AddTimeData(unsigned int ip, int64 nTime)
{
// If nobody has a time different than ours but within 5 minutes of ours, give a warning
bool fMatch = false;
- foreach(int64 nOffset, vTimeOffsets)
+ BOOST_FOREACH(int64 nOffset, vTimeOffsets)
if (nOffset != 0 && abs64(nOffset) < 5 * 60)
fMatch = true;
@@ -881,7 +870,7 @@ void AddTimeData(unsigned int ip, int64 nTime)
}
}
}
- foreach(int64 n, vTimeOffsets)
+ BOOST_FOREACH(int64 n, vTimeOffsets)
printf("%+"PRI64d" ", n);
printf("| nTimeOffset = %+"PRI64d" (%+"PRI64d" minutes)\n", nTimeOffset, nTimeOffset/60);
}