From 3b7cd5d89a226426df9c723d1f9ddfe08b7d1def Mon Sep 17 00:00:00 2001 From: s_nakamoto Date: Sun, 25 Jul 2010 16:45:21 +0000 Subject: [PATCH] Gavin Andresen's JSON-RPC HTTP authentication, 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 --- db.cpp | 36 +++++-- db.h | 4 +- headers.h | 4 + init.cpp | 85 ++++++++------- main.cpp | 38 ++++++- main.h | 17 ++- makefile.mingw | 2 +- makefile.osx | 1 + makefile.unix | 2 +- makefile.vc | 2 +- rpc.cpp | 284 +++++++++++++++++++++++++++++++++++++------------ serialize.h | 4 +- setup.nsi | 6 +- ui.cpp | 1 + uibase.h | 2 +- uiproject.fbp | 2 +- util.cpp | 41 ++++++- util.h | 11 +- 18 files changed, 405 insertions(+), 137 deletions(-) diff --git a/db.cpp b/db.cpp index 0e02e960c..ea0b581b1 100644 --- a/db.cpp +++ b/db.cpp @@ -130,7 +130,14 @@ void CDB::Close() vTxn.front()->abort(); vTxn.clear(); pdb = NULL; - dbenv.txn_checkpoint(0, 0, 0); + + // Flush database activity from memory pool to disk log + unsigned int nMinutes = 0; + 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]; @@ -357,11 +364,12 @@ CBlockIndex* InsertBlockIndex(uint256 hash) bool CTxDB::LoadBlockIndex() { - // Get cursor + // Get database cursor Dbc* pcursor = GetCursor(); if (!pcursor) return false; + // Load mapBlockIndex unsigned int fFlags = DB_SET_RANGE; loop { @@ -398,7 +406,7 @@ bool CTxDB::LoadBlockIndex() pindexNew->nBits = diskindex.nBits; pindexNew->nNonce = diskindex.nNonce; - // Watch for genesis block and best block + // Watch for genesis block if (pindexGenesisBlock == NULL && diskindex.GetBlockHash() == hashGenesisBlock) pindexGenesisBlock = pindexNew; } @@ -409,17 +417,33 @@ bool CTxDB::LoadBlockIndex() } pcursor->close(); + // Calculate bnChainWork + vector > vSortedByHeight; + vSortedByHeight.reserve(mapBlockIndex.size()); + foreach(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex) + { + CBlockIndex* pindex = item.second; + vSortedByHeight.push_back(make_pair(pindex->nHeight, pindex)); + } + sort(vSortedByHeight.begin(), vSortedByHeight.end()); + 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 found"); + return error("CTxDB::LoadBlockIndex() : hashBestChain not loaded"); } - if (!mapBlockIndex.count(hashBestChain)) - return error("CTxDB::LoadBlockIndex() : blockindex for hashBestChain not found"); + 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,16).c_str(), nBestHeight); return true; diff --git a/db.h b/db.h index 29ff1994c..0b9e6f7ef 100644 --- a/db.h +++ b/db.h @@ -16,7 +16,7 @@ extern map mapAddressBook; extern CCriticalSection cs_mapAddressBook; extern vector vchDefaultKey; extern bool fClient; - +extern int nBestHeight; extern unsigned int nWalletDBUpdated; @@ -210,7 +210,7 @@ public: if (!pdb) return false; DbTxn* ptxn = NULL; - int ret = dbenv.txn_begin(GetTxn(), &ptxn, 0); + int ret = dbenv.txn_begin(GetTxn(), &ptxn, DB_TXN_NOSYNC); if (!ptxn || ret != 0) return false; vTxn.push_back(ptxn); diff --git a/headers.h b/headers.h index 91e9dbed4..f920fd3f4 100644 --- a/headers.h +++ b/headers.h @@ -26,6 +26,7 @@ #include #include #endif +#include #include #include #include @@ -64,6 +65,9 @@ #include #include #include +#include +#include +#include #ifdef __WXMSW__ #include diff --git a/init.cpp b/init.cpp index 68e90aab0..d6d456288 100644 --- a/init.cpp +++ b/init.cpp @@ -240,33 +240,34 @@ IMPLEMENT_APP(CMyApp) bool CMyApp::Initialize(int& argc, wxChar** argv) { - if (argc > 1 && argv[1][0] != '-' && (!fWindows || argv[1][0] != '/') && - wxString(argv[1]) != "start") + for (int i = 1; i < argc; i++) + if (!IsSwitchChar(argv[i][0])) + fCommandLine = true; + + if (!fCommandLine) { - fCommandLine = true; - } - else if (!fGUI) - { - fDaemon = true; - } - else - { - // wxApp::Initialize will remove environment-specific parameters, - // so it's too early to call ParseParameters yet - for (int i = 1; i < argc; i++) + if (!fGUI) { - wxString str = argv[i]; - #ifdef __WXMSW__ - if (str.size() >= 1 && str[0] == '/') - str[0] = '-'; - char pszLower[MAX_PATH]; - strlcpy(pszLower, str.c_str(), sizeof(pszLower)); - strlwr(pszLower); - str = pszLower; - #endif - // haven't decided which argument to use for this yet - if (str == "-daemon" || str == "-d" || str == "start") - fDaemon = true; + fDaemon = true; + } + else + { + // wxApp::Initialize will remove environment-specific parameters, + // so it's too early to call ParseParameters yet + for (int i = 1; i < argc; i++) + { + wxString str = argv[i]; + #ifdef __WXMSW__ + if (str.size() >= 1 && str[0] == '/') + str[0] = '-'; + char pszLower[MAX_PATH]; + strlcpy(pszLower, str.c_str(), sizeof(pszLower)); + strlwr(pszLower); + str = pszLower; + #endif + if (str == "-daemon") + fDaemon = true; + } } } @@ -375,22 +376,23 @@ bool CMyApp::OnInit2() // // Parameters // - if (fCommandLine) - { - int ret = CommandLineRPC(argc, argv); - exit(ret); - } - ParseParameters(argc, argv); + + if (mapArgs.count("-datadir")) + strlcpy(pszSetDataDir, mapArgs["-datadir"].c_str(), sizeof(pszSetDataDir)); + + ReadConfigFile(mapArgs, mapMultiArgs); // Must be done after processing datadir + if (mapArgs.count("-?") || mapArgs.count("--help")) { wxString strUsage = string() + _("Usage:") + "\t\t\t\t\t\t\t\t\t\t\n" + - " bitcoin [options] \t" + "\n" + - " bitcoin [command] \t" + _("Send command to bitcoin running with -server or -daemon\n") + - " bitcoin [command] -? \t" + _("Get help for a command\n") + - " bitcoin help \t" + _("List commands\n") + + " bitcoin [options] \t " + "\n" + + " bitcoin [options] [params]\t " + _("Send command to -server or bitcoind\n") + + " bitcoin [options] -? \t\t " + _("Get help for a command\n") + + " bitcoin help \t\t\t " + _("List commands\n") + _("Options:\n") + + " -conf= \t " + _("Specify configuration file (default: bitcoin.conf)\n") + " -gen \t " + _("Generate coins\n") + " -gen=0 \t " + _("Don't generate coins\n") + " -min \t " + _("Start minimized\n") + @@ -398,7 +400,7 @@ bool CMyApp::OnInit2() " -proxy=\t " + _("Connect through socks4 proxy\n") + " -addnode= \t " + _("Add a node to connect to\n") + " -connect= \t " + _("Connect only to the specified node\n") + - " -rpcpw= \t " + _("Accept command line and JSON-RPC commands with the given password\n") + + " -server \t " + _("Accept command line and JSON-RPC commands\n") + " -daemon \t " + _("Run in the background as a daemon and accept commands\n") + " -? \t " + _("This help message\n"); @@ -413,15 +415,18 @@ bool CMyApp::OnInit2() return false; } - if (mapArgs.count("-datadir")) - strlcpy(pszSetDataDir, mapArgs["-datadir"].c_str(), sizeof(pszSetDataDir)); - if (mapArgs.count("-debug")) fDebug = true; if (mapArgs.count("-printtodebugger")) fPrintToDebugger = true; + if (fCommandLine) + { + int ret = CommandLineRPC(argc, argv); + exit(ret); + } + 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"); @@ -611,7 +616,7 @@ bool CMyApp::OnInit2() if (!CreateThread(StartNode, NULL)) wxMessageBox("Error: CreateThread(StartNode) failed", "Bitcoin"); - if (mapArgs.count("-server") || mapArgs.count("-rpcpw") || fDaemon) + if (mapArgs.count("-server") || fDaemon) CreateThread(ThreadRPCServer, NULL); if (fFirstRun) diff --git a/main.cpp b/main.cpp index 276a22bcd..afa7add57 100644 --- a/main.cpp +++ b/main.cpp @@ -24,6 +24,7 @@ map mapBlockIndex; const uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"); CBlockIndex* pindexGenesisBlock = NULL; int nBestHeight = -1; +CBigNum bnBestChainWork = 0; uint256 hashBestChain = 0; CBlockIndex* pindexBest = NULL; int64 nTimeBestReceived = 0; @@ -848,6 +849,23 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast) return bnNew.GetCompact(); } +vector vStartingHeight; +void AddStartingHeight(int nStartingHeight) +{ + if (nStartingHeight != -1) + { + vStartingHeight.push_back(nStartingHeight); + sort(vStartingHeight.begin(), vStartingHeight.end()); + } +} + +bool IsInitialBlockDownload() +{ + int nMedian = 69000; + if (vStartingHeight.size() >= 5) + nMedian = vStartingHeight[vStartingHeight.size()/2]; + return nBestHeight < nMedian-1000; +} @@ -1208,13 +1226,14 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos) 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)); // New best - if (pindexNew->nHeight > nBestHeight) + if (pindexNew->bnChainWork > bnBestChainWork) { if (pindexGenesisBlock == NULL && hash == hashGenesisBlock) { @@ -1253,6 +1272,7 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos) hashBestChain = hash; pindexBest = pindexNew; nBestHeight = pindexBest->nHeight; + bnBestChainWork = pindexNew->bnChainWork; nTimeBestReceived = GetTime(); nTransactionsUpdated++; printf("AddToBlockIndex: new best=%s height=%d\n", hashBestChain.ToString().substr(0,16).c_str(), nBestHeight); @@ -1900,6 +1920,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) } AddTimeData(pfrom->addr.ip, nTime); + AddStartingHeight(pfrom->nStartingHeight); // Change version if (pfrom->nVersion >= 209) @@ -2845,6 +2866,10 @@ int64 GetBalance() } +int GetRandInt(int nMax) +{ + return GetRand(nMax); +} bool SelectCoins(int64 nTargetValue, set& setCoinsRet) { @@ -2858,9 +2883,14 @@ bool SelectCoins(int64 nTargetValue, set& setCoinsRet) CRITICAL_BLOCK(cs_mapWallet) { - for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) - { - CWalletTx* pcoin = &(*it).second; + vector vCoins; + vCoins.reserve(mapWallet.size()); + for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + vCoins.push_back(&(*it).second); + random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt); + + foreach(CWalletTx* pcoin, vCoins) + { if (!pcoin->IsFinal() || pcoin->fSpent) continue; int64 n = pcoin->GetCredit(); diff --git a/main.h b/main.h index 3c10e490e..c9b240717 100644 --- a/main.h +++ b/main.h @@ -32,6 +32,7 @@ extern map mapBlockIndex; extern const uint256 hashGenesisBlock; extern CBlockIndex* pindexGenesisBlock; extern int nBestHeight; +extern CBigNum bnBestChainWork; extern uint256 hashBestChain; extern CBlockIndex* pindexBest; extern unsigned int nTransactionsUpdated; @@ -78,6 +79,7 @@ string SendMoneyToBitcoinAddress(string strAddress, int64 nValue, CWalletTx& wtx void GenerateBitcoins(bool fGenerate); void ThreadBitcoinMiner(void* parg); void BitcoinMiner(); +bool IsInitialBlockDownload(); @@ -986,11 +988,14 @@ public: // Flush stdio buffers and commit to disk before returning fflush(fileout); + if (!IsInitialBlockDownload() || (nBestHeight+1) % 500 == 0) + { #ifdef __WXMSW__ - _commit(_fileno(fileout)); + _commit(_fileno(fileout)); #else - fsync(fileno(fileout)); + fsync(fileno(fileout)); #endif + } return true; } @@ -1072,6 +1077,7 @@ public: unsigned int nFile; unsigned int nBlockPos; int nHeight; + CBigNum bnChainWork; // block header int nVersion; @@ -1089,6 +1095,7 @@ public: nFile = 0; nBlockPos = 0; nHeight = 0; + bnChainWork = 0; nVersion = 0; hashMerkleRoot = 0; @@ -1105,6 +1112,7 @@ public: nFile = nFileIn; nBlockPos = nBlockPosIn; nHeight = 0; + bnChainWork = 0; nVersion = block.nVersion; hashMerkleRoot = block.hashMerkleRoot; @@ -1118,6 +1126,11 @@ public: return *phashBlock; } + CBigNum GetBlockWork() const + { + return (CBigNum(1)<<256) / (CBigNum().SetCompact(nBits)+1); + } + bool IsInMainChain() const { return (pnext || this == pindexBest); diff --git a/makefile.mingw b/makefile.mingw index ee63d11ea..26944dfdc 100644 --- a/makefile.mingw +++ b/makefile.mingw @@ -22,7 +22,7 @@ WXLIBS= \ -l wxmsw29ud_html -l wxmsw29ud_core -l wxmsw29ud_adv -l wxbase29ud -l wxtiffd -l wxjpegd -l wxpngd -l wxzlibd LIBS= \ - -l libboost_system-mgw34-mt-d -l libboost_filesystem-mgw34-mt-d \ + -l libboost_system-mgw34-mt-d -l libboost_filesystem-mgw34-mt-d -l libboost_program_options-mgw34-mt-d \ -l db_cxx \ -l eay32 \ -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 diff --git a/makefile.osx b/makefile.osx index 264f0b162..3f5be73a3 100644 --- a/makefile.osx +++ b/makefile.osx @@ -19,6 +19,7 @@ LIBS= -dead_strip \ $(DEPSDIR)/lib/libdb_cxx-4.8.a \ $(DEPSDIR)/lib/libboost_system.a \ $(DEPSDIR)/lib/libboost_filesystem.a \ + $(DEPSDIR)/lib/libboost_program_options.a \ $(DEPSDIR)/lib/libcrypto.a WXDEFS=$(shell $(DEPSDIR)/bin/wx-config --cxxflags) -DNOPCH -DMSG_NOSIGNAL=0 diff --git a/makefile.unix b/makefile.unix index bf5b4e5b1..cc5111bbb 100644 --- a/makefile.unix +++ b/makefile.unix @@ -21,7 +21,7 @@ WXLIBS= \ LIBS= \ -Wl,-Bstatic \ - -l boost_system -l boost_filesystem \ + -l boost_system -l boost_filesystem -l boost_program_options \ -l db_cxx \ -l crypto \ -Wl,-Bdynamic \ diff --git a/makefile.vc b/makefile.vc index 9f821771e..f5452f4d0 100644 --- a/makefile.vc +++ b/makefile.vc @@ -19,7 +19,7 @@ LIBPATHS= \ /LIBPATH:"/wxwidgets/lib/vc_lib" LIBS= \ - libboost_system-vc80-mt-gd.lib libboost_filesystem-vc80-mt-gd.lib \ + libboost_system-vc80-mt-gd.lib libboost_filesystem-vc80-mt-gd.lib libboost_program_options-vc80-mt-gd.lib \ libdb47sd.lib \ libeay32.lib \ wxmsw29ud_html.lib wxmsw29ud_core.lib wxmsw29ud_adv.lib wxbase29ud.lib wxtiffd.lib wxjpegd.lib wxpngd.lib wxzlibd.lib \ diff --git a/rpc.cpp b/rpc.cpp index 5e0b5e77f..cd69a3777 100644 --- a/rpc.cpp +++ b/rpc.cpp @@ -21,7 +21,27 @@ void ThreadRPCServer2(void* parg); typedef Value(*rpcfn_type)(const Array& params, bool fHelp); extern map mapCallTable; -static string strRPCPassword; + + +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; + } +#if defined(__WXMSW__) && wxUSE_GUI + MyMessageBox(buffer, "Bitcoin", wxOK | wxICON_EXCLAMATION); +#else + fprintf(stdout, "%s", buffer); +#endif +} @@ -34,12 +54,11 @@ static string strRPCPassword; /// - Value help(const Array& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( - "help \n" + "help\n" "List commands."); string strRet; @@ -76,7 +95,7 @@ Value stop(const Array& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( - "stop \n" + "stop\n" "Stop bitcoin server."); // Shutdown will take long enough that the response should get back @@ -89,7 +108,7 @@ Value getblockcount(const Array& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( - "getblockcount \n" + "getblockcount\n" "Returns the number of blocks in the longest block chain."); return nBestHeight + 1; @@ -100,7 +119,7 @@ Value getblocknumber(const Array& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( - "getblocknumber \n" + "getblocknumber\n" "Returns the block number of the latest block in the longest block chain."); return nBestHeight; @@ -111,7 +130,7 @@ Value getconnectioncount(const Array& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( - "getconnectioncount \n" + "getconnectioncount\n" "Returns the number of connections to other nodes."); return (int)vNodes.size(); @@ -134,7 +153,7 @@ Value getdifficulty(const Array& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( - "getdifficulty \n" + "getdifficulty\n" "Returns the proof-of-work difficulty as a multiple of the minimum difficulty."); return GetDifficulty(); @@ -145,7 +164,7 @@ Value getbalance(const Array& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( - "getbalance \n" + "getbalance\n" "Returns the server's available balance."); return ((double)GetBalance() / (double)COIN); @@ -156,7 +175,7 @@ Value getgenerate(const Array& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( - "getgenerate \n" + "getgenerate\n" "Returns true or false."); return (bool)fGenerateBitcoins; @@ -167,7 +186,7 @@ Value setgenerate(const Array& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( - "setgenerate [genproclimit]\n" + "setgenerate [genproclimit]\n" " is true or false to turn generation on or off.\n" "Generation is limited to [genproclimit] processors, -1 is unlimited."); @@ -193,7 +212,7 @@ Value getinfo(const Array& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( - "getinfo "); + "getinfo"); Object obj; obj.push_back(Pair("balance", (double)GetBalance() / (double)COIN)); @@ -211,7 +230,7 @@ Value getnewaddress(const Array& params, bool fHelp) { if (fHelp || params.size() > 1) throw runtime_error( - "getnewaddress [label]\n" + "getnewaddress [label]\n" "Returns a new bitcoin address for receiving payments. " "If [label] is specified (recommended), it is added to the address book " "so payments received with the address will be labeled."); @@ -233,7 +252,7 @@ Value setlabel(const Array& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( - "setlabel