Gavin Andresen's JSON-RPC HTTP authentication,
authors_nakamoto <s_nakamoto@1a98c847-1fd6-4fd8-948a-caf3550aa51b>
Sun, 25 Jul 2010 16:45:21 +0000 (16:45 +0000)
committers_nakamoto <s_nakamoto@1a98c847-1fd6-4fd8-948a-caf3550aa51b>
Sun, 25 Jul 2010 16:45:21 +0000 (16:45 +0000)
faster initial block download
-- version 0.3.3

git-svn-id: https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk@109 1a98c847-1fd6-4fd8-948a-caf3550aa51b

18 files changed:
db.cpp
db.h
headers.h
init.cpp
main.cpp
main.h
makefile.mingw
makefile.osx
makefile.unix
makefile.vc
rpc.cpp
serialize.h
setup.nsi
ui.cpp
uibase.h
uiproject.fbp
util.cpp
util.h

diff --git a/db.cpp b/db.cpp
index 0e02e96..ea0b581 100644 (file)
--- a/db.cpp
+++ b/db.cpp
@@ -130,7 +130,14 @@ void CDB::Close()
         vTxn.front()->abort();\r
     vTxn.clear();\r
     pdb = NULL;\r
-    dbenv.txn_checkpoint(0, 0, 0);\r
+\r
+    // Flush database activity from memory pool to disk log\r
+    unsigned int nMinutes = 0;\r
+    if (strFile == "addr.dat")\r
+        nMinutes = 2;\r
+    if (strFile == "blkindex.dat" && IsInitialBlockDownload() && nBestHeight % 500 != 0)\r
+        nMinutes = 1;\r
+    dbenv.txn_checkpoint(0, nMinutes, 0);\r
 \r
     CRITICAL_BLOCK(cs_db)\r
         --mapFileUseCount[strFile];\r
@@ -357,11 +364,12 @@ CBlockIndex* InsertBlockIndex(uint256 hash)
 \r
 bool CTxDB::LoadBlockIndex()\r
 {\r
-    // Get cursor\r
+    // Get database cursor\r
     Dbc* pcursor = GetCursor();\r
     if (!pcursor)\r
         return false;\r
 \r
+    // Load mapBlockIndex\r
     unsigned int fFlags = DB_SET_RANGE;\r
     loop\r
     {\r
@@ -398,7 +406,7 @@ bool CTxDB::LoadBlockIndex()
             pindexNew->nBits          = diskindex.nBits;\r
             pindexNew->nNonce         = diskindex.nNonce;\r
 \r
-            // Watch for genesis block and best block\r
+            // Watch for genesis block\r
             if (pindexGenesisBlock == NULL && diskindex.GetBlockHash() == hashGenesisBlock)\r
                 pindexGenesisBlock = pindexNew;\r
         }\r
@@ -409,17 +417,33 @@ bool CTxDB::LoadBlockIndex()
     }\r
     pcursor->close();\r
 \r
+    // Calculate bnChainWork\r
+    vector<pair<int, CBlockIndex*> > vSortedByHeight;\r
+    vSortedByHeight.reserve(mapBlockIndex.size());\r
+    foreach(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex)\r
+    {\r
+        CBlockIndex* pindex = item.second;\r
+        vSortedByHeight.push_back(make_pair(pindex->nHeight, pindex));\r
+    }\r
+    sort(vSortedByHeight.begin(), vSortedByHeight.end());\r
+    foreach(const PAIRTYPE(int, CBlockIndex*)& item, vSortedByHeight)\r
+    {\r
+        CBlockIndex* pindex = item.second;\r
+        pindex->bnChainWork = (pindex->pprev ? pindex->pprev->bnChainWork : 0) + pindex->GetBlockWork();\r
+    }\r
+\r
+    // Load hashBestChain pointer to end of best chain\r
     if (!ReadHashBestChain(hashBestChain))\r
     {\r
         if (pindexGenesisBlock == NULL)\r
             return true;\r
-        return error("CTxDB::LoadBlockIndex() : hashBestChain not found");\r
+        return error("CTxDB::LoadBlockIndex() : hashBestChain not loaded");\r
     }\r
-\r
     if (!mapBlockIndex.count(hashBestChain))\r
-        return error("CTxDB::LoadBlockIndex() : blockindex for hashBestChain not found");\r
+        return error("CTxDB::LoadBlockIndex() : hashBestChain not found in the block index");\r
     pindexBest = mapBlockIndex[hashBestChain];\r
     nBestHeight = pindexBest->nHeight;\r
+    bnBestChainWork = pindexBest->bnChainWork;\r
     printf("LoadBlockIndex(): hashBestChain=%s  height=%d\n", hashBestChain.ToString().substr(0,16).c_str(), nBestHeight);\r
 \r
     return true;\r
diff --git a/db.h b/db.h
index 29ff199..0b9e6f7 100644 (file)
--- a/db.h
+++ b/db.h
@@ -16,7 +16,7 @@ extern map<string, string> mapAddressBook;
 extern CCriticalSection cs_mapAddressBook;\r
 extern vector<unsigned char> vchDefaultKey;\r
 extern bool fClient;\r
-\r
+extern int nBestHeight;\r
 \r
 \r
 extern unsigned int nWalletDBUpdated;\r
@@ -210,7 +210,7 @@ public:
         if (!pdb)\r
             return false;\r
         DbTxn* ptxn = NULL;\r
-        int ret = dbenv.txn_begin(GetTxn(), &ptxn, 0);\r
+        int ret = dbenv.txn_begin(GetTxn(), &ptxn, DB_TXN_NOSYNC);\r
         if (!ptxn || ret != 0)\r
             return false;\r
         vTxn.push_back(ptxn);\r
index 91e9dbe..f920fd3 100644 (file)
--- a/headers.h
+++ b/headers.h
@@ -26,6 +26,7 @@
 #include <wx/clipbrd.h>\r
 #include <wx/taskbar.h>\r
 #endif\r
+#include <openssl/buffer.h>\r
 #include <openssl/ecdsa.h>\r
 #include <openssl/evp.h>\r
 #include <openssl/rand.h>\r
@@ -64,6 +65,9 @@
 #include <boost/interprocess/sync/interprocess_recursive_mutex.hpp>\r
 #include <boost/date_time/gregorian/gregorian_types.hpp>\r
 #include <boost/date_time/posix_time/posix_time_types.hpp>\r
+#include <boost/config.hpp>\r
+#include <boost/program_options/detail/config_file.hpp>\r
+#include <boost/program_options/parsers.hpp>\r
 \r
 #ifdef __WXMSW__\r
 #include <windows.h>\r
index 68e90aa..d6d4562 100644 (file)
--- a/init.cpp
+++ b/init.cpp
@@ -240,33 +240,34 @@ IMPLEMENT_APP(CMyApp)
 \r
 bool CMyApp::Initialize(int& argc, wxChar** argv)\r
 {\r
-    if (argc > 1 && argv[1][0] != '-' && (!fWindows || argv[1][0] != '/') &&\r
-        wxString(argv[1]) != "start")\r
-    {\r
-        fCommandLine = true;\r
-    }\r
-    else if (!fGUI)\r
-    {\r
-        fDaemon = true;\r
-    }\r
-    else\r
+    for (int i = 1; i < argc; i++)\r
+        if (!IsSwitchChar(argv[i][0]))\r
+            fCommandLine = true;\r
+\r
+    if (!fCommandLine)\r
     {\r
-        // wxApp::Initialize will remove environment-specific parameters,\r
-        // so it's too early to call ParseParameters yet\r
-        for (int i = 1; i < argc; i++)\r
+        if (!fGUI)\r
+        {\r
+            fDaemon = true;\r
+        }\r
+        else\r
         {\r
-            wxString str = argv[i];\r
-            #ifdef __WXMSW__\r
-            if (str.size() >= 1 && str[0] == '/')\r
-                str[0] = '-';\r
-            char pszLower[MAX_PATH];\r
-            strlcpy(pszLower, str.c_str(), sizeof(pszLower));\r
-            strlwr(pszLower);\r
-            str = pszLower;\r
-            #endif\r
-            // haven't decided which argument to use for this yet\r
-            if (str == "-daemon" || str == "-d" || str == "start")\r
-                fDaemon = true;\r
+            // wxApp::Initialize will remove environment-specific parameters,\r
+            // so it's too early to call ParseParameters yet\r
+            for (int i = 1; i < argc; i++)\r
+            {\r
+                wxString str = argv[i];\r
+                #ifdef __WXMSW__\r
+                if (str.size() >= 1 && str[0] == '/')\r
+                    str[0] = '-';\r
+                char pszLower[MAX_PATH];\r
+                strlcpy(pszLower, str.c_str(), sizeof(pszLower));\r
+                strlwr(pszLower);\r
+                str = pszLower;\r
+                #endif\r
+                if (str == "-daemon")\r
+                    fDaemon = true;\r
+            }\r
         }\r
     }\r
 \r
@@ -375,22 +376,23 @@ bool CMyApp::OnInit2()
     //\r
     // Parameters\r
     //\r
-    if (fCommandLine)\r
-    {\r
-        int ret = CommandLineRPC(argc, argv);\r
-        exit(ret);\r
-    }\r
-\r
     ParseParameters(argc, argv);\r
+\r
+    if (mapArgs.count("-datadir"))\r
+        strlcpy(pszSetDataDir, mapArgs["-datadir"].c_str(), sizeof(pszSetDataDir));\r
+\r
+    ReadConfigFile(mapArgs, mapMultiArgs); // Must be done after processing datadir\r
+\r
     if (mapArgs.count("-?") || mapArgs.count("--help"))\r
     {\r
         wxString strUsage = string() +\r
           _("Usage:") + "\t\t\t\t\t\t\t\t\t\t\n" +\r
-            "  bitcoin [options]       \t" + "\n" +\r
-            "  bitcoin [command]       \t" + _("Send command to bitcoin running with -server or -daemon\n") +\r
-            "  bitcoin [command] -?    \t" + _("Get help for a command\n") +\r
-            "  bitcoin help <pw>       \t" + _("List commands\n") +\r
+            "  bitcoin [options]                   \t  " + "\n" +\r
+            "  bitcoin [options] <command> [params]\t  " + _("Send command to -server or bitcoind\n") +\r
+            "  bitcoin [options] <command> -?      \t\t  " + _("Get help for a command\n") +\r
+            "  bitcoin help                        \t\t\t  " + _("List commands\n") +\r
           _("Options:\n") +\r
+            "  -conf=<file>    \t  " + _("Specify configuration file (default: bitcoin.conf)\n") +\r
             "  -gen            \t  " + _("Generate coins\n") +\r
             "  -gen=0          \t  " + _("Don't generate coins\n") +\r
             "  -min            \t  " + _("Start minimized\n") +\r
@@ -398,7 +400,7 @@ bool CMyApp::OnInit2()
             "  -proxy=<ip:port>\t  " + _("Connect through socks4 proxy\n") +\r
             "  -addnode=<ip>   \t  " + _("Add a node to connect to\n") +\r
             "  -connect=<ip>   \t  " + _("Connect only to the specified node\n") +\r
-            "  -rpcpw=<pw>     \t  " + _("Accept command line and JSON-RPC commands with the given password\n") +\r
+            "  -server         \t  " + _("Accept command line and JSON-RPC commands\n") +\r
             "  -daemon         \t  " + _("Run in the background as a daemon and accept commands\n") +\r
             "  -?              \t  " + _("This help message\n");\r
 \r
@@ -413,15 +415,18 @@ bool CMyApp::OnInit2()
         return false;\r
     }\r
 \r
-    if (mapArgs.count("-datadir"))\r
-        strlcpy(pszSetDataDir, mapArgs["-datadir"].c_str(), sizeof(pszSetDataDir));\r
-\r
     if (mapArgs.count("-debug"))\r
         fDebug = true;\r
 \r
     if (mapArgs.count("-printtodebugger"))\r
         fPrintToDebugger = true;\r
 \r
+    if (fCommandLine)\r
+    {\r
+        int ret = CommandLineRPC(argc, argv);\r
+        exit(ret);\r
+    }\r
+\r
     if (!fDebug && !pszSetDataDir[0])\r
         ShrinkDebugFile();\r
     printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");\r
@@ -611,7 +616,7 @@ bool CMyApp::OnInit2()
     if (!CreateThread(StartNode, NULL))\r
         wxMessageBox("Error: CreateThread(StartNode) failed", "Bitcoin");\r
 \r
-    if (mapArgs.count("-server") || mapArgs.count("-rpcpw") || fDaemon)\r
+    if (mapArgs.count("-server") || fDaemon)\r
         CreateThread(ThreadRPCServer, NULL);\r
 \r
     if (fFirstRun)\r
index 276a22b..afa7add 100644 (file)
--- a/main.cpp
+++ b/main.cpp
@@ -24,6 +24,7 @@ map<uint256, CBlockIndex*> mapBlockIndex;
 const uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f");\r
 CBlockIndex* pindexGenesisBlock = NULL;\r
 int nBestHeight = -1;\r
+CBigNum bnBestChainWork = 0;\r
 uint256 hashBestChain = 0;\r
 CBlockIndex* pindexBest = NULL;\r
 int64 nTimeBestReceived = 0;\r
@@ -848,6 +849,23 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast)
     return bnNew.GetCompact();\r
 }\r
 \r
+vector<int> vStartingHeight;\r
+void AddStartingHeight(int nStartingHeight)\r
+{\r
+    if (nStartingHeight != -1)\r
+    {\r
+        vStartingHeight.push_back(nStartingHeight);\r
+        sort(vStartingHeight.begin(), vStartingHeight.end());\r
+    }\r
+}\r
+\r
+bool IsInitialBlockDownload()\r
+{\r
+    int nMedian = 69000;\r
+    if (vStartingHeight.size() >= 5)\r
+        nMedian = vStartingHeight[vStartingHeight.size()/2];\r
+    return nBestHeight < nMedian-1000;\r
+}\r
 \r
 \r
 \r
@@ -1208,13 +1226,14 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos)
         pindexNew->pprev = (*miPrev).second;\r
         pindexNew->nHeight = pindexNew->pprev->nHeight + 1;\r
     }\r
+    pindexNew->bnChainWork = (pindexNew->pprev ? pindexNew->pprev->bnChainWork : 0) + pindexNew->GetBlockWork();\r
 \r
     CTxDB txdb;\r
     txdb.TxnBegin();\r
     txdb.WriteBlockIndex(CDiskBlockIndex(pindexNew));\r
 \r
     // New best\r
-    if (pindexNew->nHeight > nBestHeight)\r
+    if (pindexNew->bnChainWork > bnBestChainWork)\r
     {\r
         if (pindexGenesisBlock == NULL && hash == hashGenesisBlock)\r
         {\r
@@ -1253,6 +1272,7 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos)
         hashBestChain = hash;\r
         pindexBest = pindexNew;\r
         nBestHeight = pindexBest->nHeight;\r
+        bnBestChainWork = pindexNew->bnChainWork;\r
         nTimeBestReceived = GetTime();\r
         nTransactionsUpdated++;\r
         printf("AddToBlockIndex: new best=%s  height=%d\n", hashBestChain.ToString().substr(0,16).c_str(), nBestHeight);\r
@@ -1900,6 +1920,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
         }\r
 \r
         AddTimeData(pfrom->addr.ip, nTime);\r
+        AddStartingHeight(pfrom->nStartingHeight);\r
 \r
         // Change version\r
         if (pfrom->nVersion >= 209)\r
@@ -2845,6 +2866,10 @@ int64 GetBalance()
 }\r
 \r
 \r
+int GetRandInt(int nMax)\r
+{\r
+    return GetRand(nMax);\r
+}\r
 \r
 bool SelectCoins(int64 nTargetValue, set<CWalletTx*>& setCoinsRet)\r
 {\r
@@ -2858,9 +2883,14 @@ bool SelectCoins(int64 nTargetValue, set<CWalletTx*>& setCoinsRet)
 \r
     CRITICAL_BLOCK(cs_mapWallet)\r
     {\r
-        for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)\r
-        {\r
-            CWalletTx* pcoin = &(*it).second;\r
+       vector<CWalletTx*> vCoins;\r
+       vCoins.reserve(mapWallet.size());\r
+       for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)\r
+           vCoins.push_back(&(*it).second);\r
+       random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt);\r
+\r
+       foreach(CWalletTx* pcoin, vCoins)\r
+       {\r
             if (!pcoin->IsFinal() || pcoin->fSpent)\r
                 continue;\r
             int64 n = pcoin->GetCredit();\r
diff --git a/main.h b/main.h
index 3c10e49..c9b2407 100644 (file)
--- a/main.h
+++ b/main.h
@@ -32,6 +32,7 @@ extern map<uint256, CBlockIndex*> mapBlockIndex;
 extern const uint256 hashGenesisBlock;\r
 extern CBlockIndex* pindexGenesisBlock;\r
 extern int nBestHeight;\r
+extern CBigNum bnBestChainWork;\r
 extern uint256 hashBestChain;\r
 extern CBlockIndex* pindexBest;\r
 extern unsigned int nTransactionsUpdated;\r
@@ -78,6 +79,7 @@ string SendMoneyToBitcoinAddress(string strAddress, int64 nValue, CWalletTx& wtx
 void GenerateBitcoins(bool fGenerate);\r
 void ThreadBitcoinMiner(void* parg);\r
 void BitcoinMiner();\r
+bool IsInitialBlockDownload();\r
 \r
 \r
 \r
@@ -986,11 +988,14 @@ public:
 \r
         // Flush stdio buffers and commit to disk before returning\r
         fflush(fileout);\r
+        if (!IsInitialBlockDownload() || (nBestHeight+1) % 500 == 0)\r
+        {\r
 #ifdef __WXMSW__\r
-        _commit(_fileno(fileout));\r
+            _commit(_fileno(fileout));\r
 #else\r
-        fsync(fileno(fileout));\r
+            fsync(fileno(fileout));\r
 #endif\r
+        }\r
 \r
         return true;\r
     }\r
@@ -1072,6 +1077,7 @@ public:
     unsigned int nFile;\r
     unsigned int nBlockPos;\r
     int nHeight;\r
+    CBigNum bnChainWork;\r
 \r
     // block header\r
     int nVersion;\r
@@ -1089,6 +1095,7 @@ public:
         nFile = 0;\r
         nBlockPos = 0;\r
         nHeight = 0;\r
+        bnChainWork = 0;\r
 \r
         nVersion       = 0;\r
         hashMerkleRoot = 0;\r
@@ -1105,6 +1112,7 @@ public:
         nFile = nFileIn;\r
         nBlockPos = nBlockPosIn;\r
         nHeight = 0;\r
+        bnChainWork = 0;\r
 \r
         nVersion       = block.nVersion;\r
         hashMerkleRoot = block.hashMerkleRoot;\r
@@ -1118,6 +1126,11 @@ public:
         return *phashBlock;\r
     }\r
 \r
+    CBigNum GetBlockWork() const\r
+    {\r
+        return (CBigNum(1)<<256) / (CBigNum().SetCompact(nBits)+1);\r
+    }\r
+\r
     bool IsInMainChain() const\r
     {\r
         return (pnext || this == pindexBest);\r
index ee63d11..26944df 100644 (file)
@@ -22,7 +22,7 @@ WXLIBS= \
  -l wxmsw29ud_html -l wxmsw29ud_core -l wxmsw29ud_adv -l wxbase29ud -l wxtiffd -l wxjpegd -l wxpngd -l wxzlibd\r
 \r
 LIBS= \\r
- -l libboost_system-mgw34-mt-d -l libboost_filesystem-mgw34-mt-d \\r
+ -l libboost_system-mgw34-mt-d -l libboost_filesystem-mgw34-mt-d -l libboost_program_options-mgw34-mt-d \\r
  -l db_cxx \\r
  -l eay32 \\r
  -l kernel32 -l user32 -l gdi32 -l comdlg32 -l winspool -l winmm -l shell32 -l comctl32 -l ole32 -l oleaut32 -l uuid -l rpcrt4 -l advapi32 -l ws2_32 -l shlwapi\r
index 264f0b1..3f5be73 100644 (file)
@@ -19,6 +19,7 @@ LIBS= -dead_strip \
  $(DEPSDIR)/lib/libdb_cxx-4.8.a \\r
  $(DEPSDIR)/lib/libboost_system.a \\r
  $(DEPSDIR)/lib/libboost_filesystem.a \\r
+ $(DEPSDIR)/lib/libboost_program_options.a \\r
  $(DEPSDIR)/lib/libcrypto.a \r
 \r
 WXDEFS=$(shell $(DEPSDIR)/bin/wx-config --cxxflags) -DNOPCH -DMSG_NOSIGNAL=0\r
index bf5b4e5..cc5111b 100644 (file)
@@ -21,7 +21,7 @@ WXLIBS= \
 \r
 LIBS= \\r
  -Wl,-Bstatic \\r
-   -l boost_system -l boost_filesystem \\r
+   -l boost_system -l boost_filesystem -l boost_program_options \\r
    -l db_cxx \\r
    -l crypto \\r
  -Wl,-Bdynamic \\r
index 9f82177..f5452f4 100644 (file)
@@ -19,7 +19,7 @@ LIBPATHS= \
   /LIBPATH:"/wxwidgets/lib/vc_lib"\r
 \r
 LIBS= \\r
-  libboost_system-vc80-mt-gd.lib libboost_filesystem-vc80-mt-gd.lib \\r
+  libboost_system-vc80-mt-gd.lib libboost_filesystem-vc80-mt-gd.lib libboost_program_options-vc80-mt-gd.lib \\r
   libdb47sd.lib \\r
   libeay32.lib \\r
   wxmsw29ud_html.lib wxmsw29ud_core.lib wxmsw29ud_adv.lib wxbase29ud.lib wxtiffd.lib wxjpegd.lib wxpngd.lib wxzlibd.lib \\r
diff --git a/rpc.cpp b/rpc.cpp
index 5e0b5e7..cd69a37 100644 (file)
--- a/rpc.cpp
+++ b/rpc.cpp
@@ -21,7 +21,27 @@ void ThreadRPCServer2(void* parg);
 typedef Value(*rpcfn_type)(const Array& params, bool fHelp);\r
 extern map<string, rpcfn_type> mapCallTable;\r
 \r
-static string strRPCPassword;\r
+\r
+\r
+void PrintConsole(const char* format, ...)\r
+{\r
+    char buffer[50000];\r
+    int limit = sizeof(buffer);\r
+    va_list arg_ptr;\r
+    va_start(arg_ptr, format);\r
+    int ret = _vsnprintf(buffer, limit, format, arg_ptr);\r
+    va_end(arg_ptr);\r
+    if (ret < 0 || ret >= limit)\r
+    {\r
+        ret = limit - 1;\r
+        buffer[limit-1] = 0;\r
+    }\r
+#if defined(__WXMSW__) && wxUSE_GUI\r
+    MyMessageBox(buffer, "Bitcoin", wxOK | wxICON_EXCLAMATION);\r
+#else\r
+    fprintf(stdout, "%s", buffer);\r
+#endif\r
+}\r
 \r
 \r
 \r
@@ -34,12 +54,11 @@ static string strRPCPassword;
 ///\r
 \r
 \r
-\r
 Value help(const Array& params, bool fHelp)\r
 {\r
     if (fHelp || params.size() != 0)\r
         throw runtime_error(\r
-            "help <pw>\n"\r
+            "help\n"\r
             "List commands.");\r
 \r
     string strRet;\r
@@ -76,7 +95,7 @@ Value stop(const Array& params, bool fHelp)
 {\r
     if (fHelp || params.size() != 0)\r
         throw runtime_error(\r
-            "stop <pw>\n"\r
+            "stop\n"\r
             "Stop bitcoin server.");\r
 \r
     // Shutdown will take long enough that the response should get back\r
@@ -89,7 +108,7 @@ Value getblockcount(const Array& params, bool fHelp)
 {\r
     if (fHelp || params.size() != 0)\r
         throw runtime_error(\r
-            "getblockcount <pw>\n"\r
+            "getblockcount\n"\r
             "Returns the number of blocks in the longest block chain.");\r
 \r
     return nBestHeight + 1;\r
@@ -100,7 +119,7 @@ Value getblocknumber(const Array& params, bool fHelp)
 {\r
     if (fHelp || params.size() != 0)\r
         throw runtime_error(\r
-            "getblocknumber <pw>\n"\r
+            "getblocknumber\n"\r
             "Returns the block number of the latest block in the longest block chain.");\r
 \r
     return nBestHeight;\r
@@ -111,7 +130,7 @@ Value getconnectioncount(const Array& params, bool fHelp)
 {\r
     if (fHelp || params.size() != 0)\r
         throw runtime_error(\r
-            "getconnectioncount <pw>\n"\r
+            "getconnectioncount\n"\r
             "Returns the number of connections to other nodes.");\r
 \r
     return (int)vNodes.size();\r
@@ -134,7 +153,7 @@ Value getdifficulty(const Array& params, bool fHelp)
 {\r
     if (fHelp || params.size() != 0)\r
         throw runtime_error(\r
-            "getdifficulty <pw>\n"\r
+            "getdifficulty\n"\r
             "Returns the proof-of-work difficulty as a multiple of the minimum difficulty.");\r
 \r
     return GetDifficulty();\r
@@ -145,7 +164,7 @@ Value getbalance(const Array& params, bool fHelp)
 {\r
     if (fHelp || params.size() != 0)\r
         throw runtime_error(\r
-            "getbalance <pw>\n"\r
+            "getbalance\n"\r
             "Returns the server's available balance.");\r
 \r
     return ((double)GetBalance() / (double)COIN);\r
@@ -156,7 +175,7 @@ Value getgenerate(const Array& params, bool fHelp)
 {\r
     if (fHelp || params.size() != 0)\r
         throw runtime_error(\r
-            "getgenerate <pw>\n"\r
+            "getgenerate\n"\r
             "Returns true or false.");\r
 \r
     return (bool)fGenerateBitcoins;\r
@@ -167,7 +186,7 @@ Value setgenerate(const Array& params, bool fHelp)
 {\r
     if (fHelp || params.size() < 1 || params.size() > 2)\r
         throw runtime_error(\r
-            "setgenerate <pw> <generate> [genproclimit]\n"\r
+            "setgenerate <generate> [genproclimit]\n"\r
             "<generate> is true or false to turn generation on or off.\n"\r
             "Generation is limited to [genproclimit] processors, -1 is unlimited.");\r
 \r
@@ -193,7 +212,7 @@ Value getinfo(const Array& params, bool fHelp)
 {\r
     if (fHelp || params.size() != 0)\r
         throw runtime_error(\r
-            "getinfo <pw>");\r
+            "getinfo");\r
 \r
     Object obj;\r
     obj.push_back(Pair("balance",       (double)GetBalance() / (double)COIN));\r
@@ -211,7 +230,7 @@ Value getnewaddress(const Array& params, bool fHelp)
 {\r
     if (fHelp || params.size() > 1)\r
         throw runtime_error(\r
-            "getnewaddress <pw> [label]\n"\r
+            "getnewaddress [label]\n"\r
             "Returns a new bitcoin address for receiving payments.  "\r
             "If [label] is specified (recommended), it is added to the address book "\r
             "so payments received with the address will be labeled.");\r
@@ -233,7 +252,7 @@ Value setlabel(const Array& params, bool fHelp)
 {\r
     if (fHelp || params.size() < 1 || params.size() > 2)\r
         throw runtime_error(\r
-            "setlabel <pw> <bitcoinaddress> <label>\n"\r
+            "setlabel <bitcoinaddress> <label>\n"\r
             "Sets the label associated with the given address.");\r
 \r
     string strAddress = params[0].get_str();\r
@@ -250,7 +269,7 @@ Value getlabel(const Array& params, bool fHelp)
 {\r
     if (fHelp || params.size() != 1)\r
         throw runtime_error(\r
-            "getlabel <pw> <bitcoinaddress>\n"\r
+            "getlabel <bitcoinaddress>\n"\r
             "Returns the label associated with the given address.");\r
 \r
     string strAddress = params[0].get_str();\r
@@ -270,7 +289,7 @@ Value getaddressesbylabel(const Array& params, bool fHelp)
 {\r
     if (fHelp || params.size() != 1)\r
         throw runtime_error(\r
-            "getaddressesbylabel <pw> <label>\n"\r
+            "getaddressesbylabel <label>\n"\r
             "Returns the list of addresses with the given label.");\r
 \r
     string strLabel = params[0].get_str();\r
@@ -300,7 +319,7 @@ Value sendtoaddress(const Array& params, bool fHelp)
 {\r
     if (fHelp || params.size() < 2 || params.size() > 4)\r
         throw runtime_error(\r
-            "sendtoaddress <pw> <bitcoinaddress> <amount> [comment] [comment-to]\n"\r
+            "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"\r
             "<amount> is a real and is rounded to the nearest 0.01");\r
 \r
     string strAddress = params[0].get_str();\r
@@ -328,7 +347,7 @@ Value listtransactions(const Array& params, bool fHelp)
 {\r
     if (fHelp || params.size() > 2)\r
         throw runtime_error(\r
-            "listtransactions <pw> [count=10] [includegenerated=false]\n"\r
+            "listtransactions [count=10] [includegenerated=false]\n"\r
             "Returns up to [count] most recent transactions.");\r
 \r
     int64 nCount = 10;\r
@@ -349,7 +368,7 @@ Value getreceivedbyaddress(const Array& params, bool fHelp)
 {\r
     if (fHelp || params.size() < 1 || params.size() > 2)\r
         throw runtime_error(\r
-            "getreceivedbyaddress <pw> <bitcoinaddress> [minconf=1]\n"\r
+            "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"\r
             "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");\r
 \r
     // Bitcoin address\r
@@ -390,7 +409,7 @@ Value getreceivedbylabel(const Array& params, bool fHelp)
 {\r
     if (fHelp || params.size() < 1 || params.size() > 2)\r
         throw runtime_error(\r
-            "getreceivedbylabel <pw> <label> [minconf=1]\n"\r
+            "getreceivedbylabel <label> [minconf=1]\n"\r
             "Returns the total amount received by addresses with <label> in transactions with at least [minconf] confirmations.");\r
 \r
     // Get the set of pub keys that have the label\r
@@ -553,7 +572,7 @@ Value listreceivedbyaddress(const Array& params, bool fHelp)
 {\r
     if (fHelp || params.size() > 2)\r
         throw runtime_error(\r
-            "listreceivedbyaddress <pw> [minconf=1] [includeempty=false]\n"\r
+            "listreceivedbyaddress [minconf=1] [includeempty=false]\n"\r
             "[minconf] is the minimum number of confirmations before payments are included.\n"\r
             "[includeempty] whether to include addresses that haven't received any payments.\n"\r
             "Returns an array of objects containing:\n"\r
@@ -569,7 +588,7 @@ Value listreceivedbylabel(const Array& params, bool fHelp)
 {\r
     if (fHelp || params.size() > 2)\r
         throw runtime_error(\r
-            "listreceivedbylabel <pw> [minconf=1] [includeempty=false]\n"\r
+            "listreceivedbylabel [minconf=1] [includeempty=false]\n"\r
             "[minconf] is the minimum number of confirmations before payments are included.\n"\r
             "[includeempty] whether to include labels that haven't received any payments.\n"\r
             "Returns an array of objects containing:\n"\r
@@ -632,23 +651,41 @@ map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)
 // and to be compatible with other JSON-RPC implementations.\r
 //\r
 \r
-string HTTPPost(const string& strMsg)\r
+string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)\r
 {\r
-    return strprintf(\r
-            "POST / HTTP/1.1\r\n"\r
-            "User-Agent: json-rpc/1.0\r\n"\r
-            "Host: 127.0.0.1\r\n"\r
-            "Content-Type: application/json\r\n"\r
-            "Content-Length: %d\r\n"\r
-            "Accept: application/json\r\n"\r
-            "\r\n"\r
-            "%s",\r
-        strMsg.size(),\r
-        strMsg.c_str());\r
+    ostringstream s;\r
+    s << "POST / HTTP/1.1\r\n"\r
+      << "User-Agent: json-rpc/1.0\r\n"\r
+      << "Host: 127.0.0.1\r\n"\r
+      << "Content-Type: application/json\r\n"\r
+      << "Content-Length: " << strMsg.size() << "\r\n"\r
+      << "Accept: application/json\r\n";\r
+    for (map<string,string>::const_iterator it = mapRequestHeaders.begin(); it != mapRequestHeaders.end(); ++it)\r
+        s << it->first << ": " << it->second << "\r\n";\r
+    s << "\r\n" << strMsg;\r
+\r
+    return s.str();\r
 }\r
 \r
 string HTTPReply(const string& strMsg, int nStatus=200)\r
 {\r
+    if (nStatus == 401)\r
+        return "HTTP/1.0 401 Authorization Required\r\n"\r
+            "Server: HTTPd/1.0\r\n"\r
+            "Date: Sat, 08 Jul 2006 12:04:08 GMT\r\n"\r
+            "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"\r
+            "Content-Type: text/html\r\n"\r
+            "Content-Length: 311\r\n"\r
+            "\r\n"\r
+            "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"\r
+            "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"\r
+            "<HTML>\r\n"\r
+            "<HEAD>\r\n"\r
+            "<TITLE>Error</TITLE>\r\n"\r
+            "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"\r
+            "</HEAD>\r\n"\r
+            "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"\r
+            "</HTML>\r\n";\r
     string strStatus;\r
     if (nStatus == 200) strStatus = "OK";\r
     if (nStatus == 500) strStatus = "Internal Server Error";\r
@@ -667,7 +704,17 @@ string HTTPReply(const string& strMsg, int nStatus=200)
         strMsg.c_str());\r
 }\r
 \r
-int ReadHTTPHeader(tcp::iostream& stream)\r
+int ReadHTTPStatus(tcp::iostream& stream)\r
+{\r
+    string str;\r
+    getline(stream, str);\r
+    vector<string> vWords;\r
+    boost::split(vWords, str, boost::is_any_of(" "));\r
+    int nStatus = atoi(vWords[1].c_str());\r
+    return nStatus;\r
+}\r
+\r
+int ReadHTTPHeader(tcp::iostream& stream, map<string, string>& mapHeadersRet)\r
 {\r
     int nLen = 0;\r
     loop\r
@@ -676,26 +723,92 @@ int ReadHTTPHeader(tcp::iostream& stream)
         std::getline(stream, str);\r
         if (str.empty() || str == "\r")\r
             break;\r
-        if (str.substr(0,15) == "Content-Length:")\r
-            nLen = atoi(str.substr(15));\r
+        string::size_type nColon = str.find(":");\r
+        if (nColon != string::npos)\r
+        {\r
+            string strHeader = str.substr(0, nColon);\r
+            boost::trim(strHeader);\r
+            string strValue = str.substr(nColon+1);\r
+            boost::trim(strValue);\r
+            mapHeadersRet[strHeader] = strValue;\r
+            if (strHeader == "Content-Length")\r
+                nLen = atoi(strValue.c_str());\r
+        }\r
     }\r
     return nLen;\r
 }\r
 \r
-inline string ReadHTTP(tcp::iostream& stream)\r
+int ReadHTTP(tcp::iostream& stream, map<string, string>& mapHeadersRet, string& strMessageRet)\r
 {\r
+    mapHeadersRet.clear();\r
+    strMessageRet = "";\r
+\r
+    // Read status\r
+    int nStatus = ReadHTTPStatus(stream);\r
+\r
     // Read header\r
-    int nLen = ReadHTTPHeader(stream);\r
+    int nLen = ReadHTTPHeader(stream, mapHeadersRet);\r
     if (nLen <= 0)\r
-        return string();\r
+        return 500;\r
 \r
     // Read message\r
     vector<char> vch(nLen);\r
     stream.read(&vch[0], nLen);\r
-    return string(vch.begin(), vch.end());\r
+    strMessageRet = string(vch.begin(), vch.end());\r
+\r
+    return nStatus;\r
 }\r
 \r
+string EncodeBase64(string s)\r
+{\r
+    BIO *b64, *bmem;\r
+    BUF_MEM *bptr;\r
+\r
+    b64 = BIO_new(BIO_f_base64());\r
+    bmem = BIO_new(BIO_s_mem());\r
+    b64 = BIO_push(b64, bmem);\r
+    BIO_write(b64, s.c_str(), s.size());\r
+    BIO_flush(b64);\r
+    BIO_get_mem_ptr(b64, &bptr);\r
 \r
+    string result(bptr->data, bptr->length-1);\r
+    BIO_free_all(b64);\r
+\r
+    return result;\r
+}\r
+\r
+string DecodeBase64(string s)\r
+{\r
+    BIO *b64, *bmem;\r
+\r
+    char* buffer = static_cast<char*>(calloc(s.size(), sizeof(char)));\r
+\r
+    b64 = BIO_new(BIO_f_base64());\r
+    BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);\r
+    bmem = BIO_new_mem_buf(const_cast<char*>(s.c_str()), s.size());\r
+    bmem = BIO_push(b64, bmem);\r
+    BIO_read(bmem, buffer, s.size());\r
+    BIO_free_all(bmem);\r
+\r
+    string result(buffer);\r
+    free(buffer);\r
+    return result;\r
+}\r
+\r
+bool HTTPAuthorized(map<string, string>& mapHeaders)\r
+{\r
+    string strAuth = mapHeaders["Authorization"];\r
+    if (strAuth.substr(0,6) != "Basic ")\r
+        return false;\r
+    string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);\r
+    string strUserPass = DecodeBase64(strUserPass64);\r
+    string::size_type nColon = strUserPass.find(":");\r
+    if (nColon == string::npos)\r
+        return false;\r
+    string strUser = strUserPass.substr(0, nColon);\r
+    string strPassword = strUserPass.substr(nColon+1);\r
+    return (strUser == mapArgs["-rpcuser"] && strPassword == mapArgs["-rpcpassword"]);\r
+}\r
 \r
 //\r
 // JSON-RPC protocol\r
@@ -751,15 +864,20 @@ void ThreadRPCServer2(void* parg)
 {\r
     printf("ThreadRPCServer started\n");\r
 \r
-    if (mapArgs.count("-rpcpw"))\r
-        strRPCPassword = mapArgs["-rpcpw"];\r
-    if (strRPCPassword == "")\r
+    if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")\r
     {\r
-#if defined(__WXMSW__) && wxUSE_GUI\r
-        MyMessageBox("Warning: rpc password is blank, use -rpcpw=<password>\n", "Bitcoin", wxOK | wxICON_EXCLAMATION);\r
-#else\r
-        fprintf(stdout, "Warning: rpc password is blank, use -rpcpw=<password>\n");\r
-#endif\r
+        string strWhatAmI = "To use bitcoind";\r
+        if (mapArgs.count("-server"))\r
+            strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");\r
+        else if (mapArgs.count("-daemon"))\r
+            strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");\r
+        PrintConsole(\r
+            _("Warning: %s, you must set rpcpassword=<password>\nin the configuration file: %s\n"\r
+              "If the file does not exist, create it with owner-readable-only file permissions.\n"),\r
+                strWhatAmI.c_str(),\r
+                GetConfigFile().c_str());\r
+        CreateThread(Shutdown, NULL);\r
+        return;\r
     }\r
 \r
     // Bind to loopback 127.0.0.1 so the socket can only be accessed locally\r
@@ -783,7 +901,26 @@ void ThreadRPCServer2(void* parg)
             continue;\r
 \r
         // Receive request\r
-        string strRequest = ReadHTTP(stream);\r
+        map<string, string> mapHeaders;\r
+        string strRequest;\r
+        ReadHTTP(stream, mapHeaders, strRequest);\r
+\r
+        // Check authorization\r
+        if (mapHeaders.count("Authorization") == 0)\r
+        {\r
+            stream << HTTPReply("", 401) << std::flush;\r
+            continue;\r
+        }\r
+        if (!HTTPAuthorized(mapHeaders))\r
+        {\r
+            // Deter brute-forcing short passwords\r
+            if (mapArgs["-rpcpassword"].size() < 15)\r
+                Sleep(50);\r
+\r
+            stream << HTTPReply("", 401) << std::flush;\r
+            printf("ThreadRPCServer incorrect password attempt\n");\r
+            continue;\r
+        }\r
 \r
         // Handle multiple invocations per request\r
         string::iterator begin = strRequest.begin();\r
@@ -808,23 +945,11 @@ void ThreadRPCServer2(void* parg)
 \r
                 printf("ThreadRPCServer method=%s\n", strMethod.c_str());\r
 \r
-                // Check password\r
-                if (params.size() < 1 || params[0].type() != str_type)\r
-                    throw runtime_error("First parameter must be the password.");\r
-                if (params[0].get_str() != strRPCPassword)\r
-                {\r
-                    if (strRPCPassword.size() < 15)\r
-                        Sleep(50);\r
-                    begin = strRequest.end();\r
-                    printf("ThreadRPCServer incorrect password attempt\n");\r
-                    throw runtime_error("Incorrect password.");\r
-                }\r
-\r
                 // Execute\r
                 map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);\r
                 if (mi == mapCallTable.end())\r
                     throw runtime_error("Method not found.");\r
-                Value result = (*(*mi).second)(Array(params.begin()+1, params.end()), false);\r
+                Value result = (*(*mi).second)(params, false);\r
 \r
                 // Send reply\r
                 string strReply = JSONRPCReply(result, Value::null, id);\r
@@ -847,18 +972,36 @@ void ThreadRPCServer2(void* parg)
 \r
 Value CallRPC(const string& strMethod, const Array& params)\r
 {\r
+    if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")\r
+        throw runtime_error(strprintf(\r
+            _("You must set rpcpassword=<password> in the configuration file:\n%s\n"\r
+              "If the file does not exist, create it with owner-readable-only file permissions."),\r
+                GetConfigFile().c_str()));\r
+\r
     // Connect to localhost\r
     tcp::iostream stream("127.0.0.1", "8332");\r
     if (stream.fail())\r
         throw runtime_error("couldn't connect to server");\r
 \r
+    // HTTP basic authentication\r
+    string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);\r
+    map<string, string> mapRequestHeaders;\r
+    mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;\r
+\r
     // Send request\r
     string strRequest = JSONRPCRequest(strMethod, params, 1);\r
-    stream << HTTPPost(strRequest) << std::flush;\r
+    string strPost = HTTPPost(strRequest, mapRequestHeaders);\r
+    stream << strPost << std::flush;\r
 \r
     // Receive reply\r
-    string strReply = ReadHTTP(stream);\r
-    if (strReply.empty())\r
+    map<string, string> mapHeaders;\r
+    string strReply;\r
+    int nStatus = ReadHTTP(stream, mapHeaders, strReply);\r
+    if (nStatus == 401)\r
+        throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");\r
+    else if (nStatus >= 400 && nStatus != 500)\r
+        throw runtime_error(strprintf("server returned HTTP error %d", nStatus));\r
+    else if (strReply.empty())\r
         throw runtime_error("no response from server");\r
 \r
     // Parse reply\r
@@ -904,7 +1047,14 @@ int CommandLineRPC(int argc, char *argv[])
 {\r
     try\r
     {\r
-        // Check that method exists\r
+        // Skip switches\r
+        while (argc > 1 && IsSwitchChar(argv[1][0]))\r
+        {\r
+            argc--;\r
+            argv++;\r
+        }\r
+\r
+        // Check that the method exists\r
         if (argc < 2)\r
             throw runtime_error("too few parameters");\r
         string strMethod = argv[1];\r
index 4a7eec6..dd2127c 100644 (file)
@@ -19,8 +19,8 @@ class CScript;
 class CDataStream;\r
 class CAutoFile;\r
 \r
-static const int VERSION = 302;\r
-static const char* pszSubVer = ".2";\r
+static const int VERSION = 303;\r
+static const char* pszSubVer = "";\r
 \r
 \r
 \r
index ff6763e..f03756f 100644 (file)
--- a/setup.nsi
+++ b/setup.nsi
@@ -7,7 +7,7 @@ RequestExecutionLevel highest
 \r
 # General Symbol Definitions\r
 !define REGKEY "SOFTWARE\$(^Name)"\r
-!define VERSION 0.3.2\r
+!define VERSION 0.3.3\r
 !define COMPANY "Bitcoin project"\r
 !define URL http://www.bitcoin.org/\r
 \r
@@ -42,12 +42,12 @@ Var StartMenuGroup
 !insertmacro MUI_LANGUAGE English\r
 \r
 # Installer attributes\r
-OutFile bitcoin-0.3.2-win32-setup.exe\r
+OutFile bitcoin-0.3.3-win32-setup.exe\r
 InstallDir $PROGRAMFILES\Bitcoin\r
 CRCCheck on\r
 XPStyle on\r
 ShowInstDetails show\r
-VIProductVersion 0.3.2.0\r
+VIProductVersion 0.3.3.0\r
 VIAddVersionKey ProductName Bitcoin\r
 VIAddVersionKey ProductVersion "${VERSION}"\r
 VIAddVersionKey CompanyName "${COMPANY}"\r
diff --git a/ui.cpp b/ui.cpp
index 5d0815e..0ba6a10 100644 (file)
--- a/ui.cpp
+++ b/ui.cpp
@@ -1614,6 +1614,7 @@ void COptionsDialog::OnButtonApply(wxCommandEvent& event)
 CAboutDialog::CAboutDialog(wxWindow* parent) : CAboutDialogBase(parent)\r
 {\r
     m_staticTextVersion->SetLabel(strprintf(_("version %d.%d.%d beta"), VERSION/10000, (VERSION/100)%100, VERSION%100));\r
+    //m_staticTextVersion->SetLabel(strprintf(_("version %d.%d.%d%s beta"), VERSION/10000, (VERSION/100)%100, VERSION%100, pszSubVer));\r
 \r
     // Change (c) into UTF-8 or ANSI copyright symbol\r
     wxString str = m_staticTextMain->GetLabel();\r
index 10c438c..e28ac9f 100644 (file)
--- a/uibase.h
+++ b/uibase.h
@@ -227,7 +227,7 @@ class CAboutDialogBase : public wxDialog
        \r
        public:\r
                wxStaticText* m_staticTextVersion;\r
-               CAboutDialogBase( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("About Bitcoin"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 532,329 ), long style = wxDEFAULT_DIALOG_STYLE );\r
+               CAboutDialogBase( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("About Bitcoin"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 532,333 ), long style = wxDEFAULT_DIALOG_STYLE );\r
                ~CAboutDialogBase();\r
        \r
 };\r
index 4753924..ac7bbd6 100644 (file)
             <property name="minimum_size"></property>\r
             <property name="name">CAboutDialogBase</property>\r
             <property name="pos"></property>\r
-            <property name="size">532,329</property>\r
+            <property name="size">532,333</property>\r
             <property name="style">wxDEFAULT_DIALOG_STYLE</property>\r
             <property name="subclass"></property>\r
             <property name="title">About Bitcoin</property>\r
index 4ddc525..5d3728a 100644 (file)
--- a/util.cpp
+++ b/util.cpp
@@ -416,7 +416,7 @@ void ParseParameters(int argc, char* argv[])
 {\r
     mapArgs.clear();\r
     mapMultiArgs.clear();\r
-    for (int i = 0; i < argc; i++)\r
+    for (int i = 1; i < argc; i++)\r
     {\r
         char psz[10000];\r
         strlcpy(psz, argv[i], sizeof(psz));\r
@@ -431,6 +431,8 @@ void ParseParameters(int argc, char* argv[])
         if (psz[0] == '/')\r
             psz[0] = '-';\r
         #endif\r
+        if (psz[0] != '-')\r
+            break;\r
         mapArgs[psz] = pszValue;\r
         mapMultiArgs[psz].push_back(pszValue);\r
     }\r
@@ -619,6 +621,38 @@ string GetDataDir()
     return pszDir;\r
 }\r
 \r
+string GetConfigFile()\r
+{\r
+    namespace fs = boost::filesystem;\r
+    fs::path pathConfig(mapArgs.count("-conf") ? mapArgs["-conf"] : string("bitcoin.conf"));\r
+    if (!pathConfig.is_complete())\r
+        pathConfig = fs::path(GetDataDir()) / pathConfig;\r
+    return pathConfig.string();\r
+}\r
+\r
+void ReadConfigFile(map<string, string>& mapSettingsRet,\r
+                    map<string, vector<string> >& mapMultiSettingsRet)\r
+{\r
+    namespace fs = boost::filesystem;\r
+    namespace pod = boost::program_options::detail;\r
+\r
+    fs::ifstream streamConfig(GetConfigFile());\r
+    if (!streamConfig.good())\r
+        return;\r
+\r
+    set<string> setOptions;\r
+    setOptions.insert("*");\r
+    \r
+    for (pod::config_file_iterator it(streamConfig, setOptions), end; it != end; ++it)\r
+    {\r
+        // Don't overwrite existing settings so command line settings override bitcoin.conf\r
+        string strKey = string("-") + it->string_key;\r
+        if (mapSettingsRet.count(strKey) == 0)\r
+            mapSettingsRet[strKey] = it->value[0];\r
+        mapMultiSettingsRet[strKey].push_back(it->value[0]);\r
+    }\r
+}\r
+\r
 int GetFilesize(FILE* file)\r
 {\r
     int nSavePos = ftell(file);\r
@@ -656,9 +690,6 @@ void ShrinkDebugFile()
 \r
 \r
 \r
-\r
-\r
-\r
 //\r
 // "Never go to sea with two chronometers; take one or three."\r
 // Our three chronometers are:\r
@@ -701,7 +732,7 @@ void AddTimeData(unsigned int ip, int64 nTime)
         sort(vTimeOffsets.begin(), vTimeOffsets.end());\r
         int64 nMedian = vTimeOffsets[vTimeOffsets.size()/2];\r
         nTimeOffset = nMedian;\r
-        if ((nMedian > 0 ? nMedian : -nMedian) > 36 * 60 * 60)\r
+        if ((nMedian > 0 ? nMedian : -nMedian) > 70 * 60)\r
         {\r
             // Only let other nodes change our clock so far before we\r
             // go to the NTP servers\r
diff --git a/util.h b/util.h
index 030a1d7..49e3863 100644 (file)
--- a/util.h
+++ b/util.h
@@ -141,6 +141,8 @@ void ParseParameters(int argc, char* argv[]);
 const char* wxGetTranslation(const char* psz);\r
 int GetFilesize(FILE* file);\r
 void GetDataDir(char* pszDirRet);\r
+string GetConfigFile();\r
+void ReadConfigFile(map<string, string>& mapSettingsRet, map<string, vector<string> >& mapMultiSettingsRet);\r
 #ifdef __WXMSW__\r
 string MyGetSpecialFolderPath(int nFolder, bool fCreate);\r
 #endif\r
@@ -348,7 +350,14 @@ void skipspaces(T& it)
         ++it;\r
 }\r
 \r
-\r
+inline bool IsSwitchChar(char c)\r
+{\r
+#ifdef __WXMSW__\r
+    return c == '-' || c == '/';\r
+#else\r
+    return c == '-';\r
+#endif\r
+}\r
 \r
 \r
 \r