Browse Source

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
miguelfreitas
s_nakamoto 15 years ago
parent
commit
3b7cd5d89a
  1. 36
      db.cpp
  2. 4
      db.h
  3. 4
      headers.h
  4. 85
      init.cpp
  5. 38
      main.cpp
  6. 17
      main.h
  7. 2
      makefile.mingw
  8. 1
      makefile.osx
  9. 2
      makefile.unix
  10. 2
      makefile.vc
  11. 284
      rpc.cpp
  12. 4
      serialize.h
  13. 6
      setup.nsi
  14. 1
      ui.cpp
  15. 2
      uibase.h
  16. 2
      uiproject.fbp
  17. 41
      util.cpp
  18. 11
      util.h

36
db.cpp

@ -130,7 +130,14 @@ void CDB::Close()
vTxn.front()->abort(); vTxn.front()->abort();
vTxn.clear(); vTxn.clear();
pdb = NULL; 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) CRITICAL_BLOCK(cs_db)
--mapFileUseCount[strFile]; --mapFileUseCount[strFile];
@ -357,11 +364,12 @@ CBlockIndex* InsertBlockIndex(uint256 hash)
bool CTxDB::LoadBlockIndex() bool CTxDB::LoadBlockIndex()
{ {
// Get cursor // Get database cursor
Dbc* pcursor = GetCursor(); Dbc* pcursor = GetCursor();
if (!pcursor) if (!pcursor)
return false; return false;
// Load mapBlockIndex
unsigned int fFlags = DB_SET_RANGE; unsigned int fFlags = DB_SET_RANGE;
loop loop
{ {
@ -398,7 +406,7 @@ bool CTxDB::LoadBlockIndex()
pindexNew->nBits = diskindex.nBits; pindexNew->nBits = diskindex.nBits;
pindexNew->nNonce = diskindex.nNonce; pindexNew->nNonce = diskindex.nNonce;
// Watch for genesis block and best block // Watch for genesis block
if (pindexGenesisBlock == NULL && diskindex.GetBlockHash() == hashGenesisBlock) if (pindexGenesisBlock == NULL && diskindex.GetBlockHash() == hashGenesisBlock)
pindexGenesisBlock = pindexNew; pindexGenesisBlock = pindexNew;
} }
@ -409,17 +417,33 @@ bool CTxDB::LoadBlockIndex()
} }
pcursor->close(); pcursor->close();
// Calculate bnChainWork
vector<pair<int, CBlockIndex*> > 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 (!ReadHashBestChain(hashBestChain))
{ {
if (pindexGenesisBlock == NULL) if (pindexGenesisBlock == NULL)
return true; return true;
return error("CTxDB::LoadBlockIndex() : hashBestChain not found"); return error("CTxDB::LoadBlockIndex() : hashBestChain not loaded");
} }
if (!mapBlockIndex.count(hashBestChain)) 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]; pindexBest = mapBlockIndex[hashBestChain];
nBestHeight = pindexBest->nHeight; nBestHeight = pindexBest->nHeight;
bnBestChainWork = pindexBest->bnChainWork;
printf("LoadBlockIndex(): hashBestChain=%s height=%d\n", hashBestChain.ToString().substr(0,16).c_str(), nBestHeight); printf("LoadBlockIndex(): hashBestChain=%s height=%d\n", hashBestChain.ToString().substr(0,16).c_str(), nBestHeight);
return true; return true;

4
db.h

@ -16,7 +16,7 @@ extern map<string, string> mapAddressBook;
extern CCriticalSection cs_mapAddressBook; extern CCriticalSection cs_mapAddressBook;
extern vector<unsigned char> vchDefaultKey; extern vector<unsigned char> vchDefaultKey;
extern bool fClient; extern bool fClient;
extern int nBestHeight;
extern unsigned int nWalletDBUpdated; extern unsigned int nWalletDBUpdated;
@ -210,7 +210,7 @@ public:
if (!pdb) if (!pdb)
return false; return false;
DbTxn* ptxn = NULL; 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) if (!ptxn || ret != 0)
return false; return false;
vTxn.push_back(ptxn); vTxn.push_back(ptxn);

4
headers.h

@ -26,6 +26,7 @@
#include <wx/clipbrd.h> #include <wx/clipbrd.h>
#include <wx/taskbar.h> #include <wx/taskbar.h>
#endif #endif
#include <openssl/buffer.h>
#include <openssl/ecdsa.h> #include <openssl/ecdsa.h>
#include <openssl/evp.h> #include <openssl/evp.h>
#include <openssl/rand.h> #include <openssl/rand.h>
@ -64,6 +65,9 @@
#include <boost/interprocess/sync/interprocess_recursive_mutex.hpp> #include <boost/interprocess/sync/interprocess_recursive_mutex.hpp>
#include <boost/date_time/gregorian/gregorian_types.hpp> #include <boost/date_time/gregorian/gregorian_types.hpp>
#include <boost/date_time/posix_time/posix_time_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__ #ifdef __WXMSW__
#include <windows.h> #include <windows.h>

85
init.cpp

@ -240,33 +240,34 @@ IMPLEMENT_APP(CMyApp)
bool CMyApp::Initialize(int& argc, wxChar** argv) bool CMyApp::Initialize(int& argc, wxChar** argv)
{ {
if (argc > 1 && argv[1][0] != '-' && (!fWindows || argv[1][0] != '/') && for (int i = 1; i < argc; i++)
wxString(argv[1]) != "start") if (!IsSwitchChar(argv[i][0]))
{ fCommandLine = true;
fCommandLine = true;
} if (!fCommandLine)
else if (!fGUI)
{
fDaemon = true;
}
else
{ {
// wxApp::Initialize will remove environment-specific parameters, if (!fGUI)
// so it's too early to call ParseParameters yet {
for (int i = 1; i < argc; i++) fDaemon = true;
}
else
{ {
wxString str = argv[i]; // wxApp::Initialize will remove environment-specific parameters,
#ifdef __WXMSW__ // so it's too early to call ParseParameters yet
if (str.size() >= 1 && str[0] == '/') for (int i = 1; i < argc; i++)
str[0] = '-'; {
char pszLower[MAX_PATH]; wxString str = argv[i];
strlcpy(pszLower, str.c_str(), sizeof(pszLower)); #ifdef __WXMSW__
strlwr(pszLower); if (str.size() >= 1 && str[0] == '/')
str = pszLower; str[0] = '-';
#endif char pszLower[MAX_PATH];
// haven't decided which argument to use for this yet strlcpy(pszLower, str.c_str(), sizeof(pszLower));
if (str == "-daemon" || str == "-d" || str == "start") strlwr(pszLower);
fDaemon = true; str = pszLower;
#endif
if (str == "-daemon")
fDaemon = true;
}
} }
} }
@ -375,22 +376,23 @@ bool CMyApp::OnInit2()
// //
// Parameters // Parameters
// //
if (fCommandLine)
{
int ret = CommandLineRPC(argc, argv);
exit(ret);
}
ParseParameters(argc, argv); 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")) if (mapArgs.count("-?") || mapArgs.count("--help"))
{ {
wxString strUsage = string() + wxString strUsage = string() +
_("Usage:") + "\t\t\t\t\t\t\t\t\t\t\n" + _("Usage:") + "\t\t\t\t\t\t\t\t\t\t\n" +
" bitcoin [options] \t" + "\n" + " bitcoin [options] \t " + "\n" +
" bitcoin [command] \t" + _("Send command to bitcoin running with -server or -daemon\n") + " bitcoin [options] <command> [params]\t " + _("Send command to -server or bitcoind\n") +
" bitcoin [command] -? \t" + _("Get help for a command\n") + " bitcoin [options] <command> -? \t\t " + _("Get help for a command\n") +
" bitcoin help <pw> \t" + _("List commands\n") + " bitcoin help \t\t\t " + _("List commands\n") +
_("Options:\n") + _("Options:\n") +
" -conf=<file> \t " + _("Specify configuration file (default: bitcoin.conf)\n") +
" -gen \t " + _("Generate coins\n") + " -gen \t " + _("Generate coins\n") +
" -gen=0 \t " + _("Don't generate coins\n") + " -gen=0 \t " + _("Don't generate coins\n") +
" -min \t " + _("Start minimized\n") + " -min \t " + _("Start minimized\n") +
@ -398,7 +400,7 @@ bool CMyApp::OnInit2()
" -proxy=<ip:port>\t " + _("Connect through socks4 proxy\n") + " -proxy=<ip:port>\t " + _("Connect through socks4 proxy\n") +
" -addnode=<ip> \t " + _("Add a node to connect to\n") + " -addnode=<ip> \t " + _("Add a node to connect to\n") +
" -connect=<ip> \t " + _("Connect only to the specified node\n") + " -connect=<ip> \t " + _("Connect only to the specified node\n") +
" -rpcpw=<pw> \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") + " -daemon \t " + _("Run in the background as a daemon and accept commands\n") +
" -? \t " + _("This help message\n"); " -? \t " + _("This help message\n");
@ -413,15 +415,18 @@ bool CMyApp::OnInit2()
return false; return false;
} }
if (mapArgs.count("-datadir"))
strlcpy(pszSetDataDir, mapArgs["-datadir"].c_str(), sizeof(pszSetDataDir));
if (mapArgs.count("-debug")) if (mapArgs.count("-debug"))
fDebug = true; fDebug = true;
if (mapArgs.count("-printtodebugger")) if (mapArgs.count("-printtodebugger"))
fPrintToDebugger = true; fPrintToDebugger = true;
if (fCommandLine)
{
int ret = CommandLineRPC(argc, argv);
exit(ret);
}
if (!fDebug && !pszSetDataDir[0]) if (!fDebug && !pszSetDataDir[0])
ShrinkDebugFile(); ShrinkDebugFile();
printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); 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)) if (!CreateThread(StartNode, NULL))
wxMessageBox("Error: CreateThread(StartNode) failed", "Bitcoin"); wxMessageBox("Error: CreateThread(StartNode) failed", "Bitcoin");
if (mapArgs.count("-server") || mapArgs.count("-rpcpw") || fDaemon) if (mapArgs.count("-server") || fDaemon)
CreateThread(ThreadRPCServer, NULL); CreateThread(ThreadRPCServer, NULL);
if (fFirstRun) if (fFirstRun)

38
main.cpp

@ -24,6 +24,7 @@ map<uint256, CBlockIndex*> mapBlockIndex;
const uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"); const uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f");
CBlockIndex* pindexGenesisBlock = NULL; CBlockIndex* pindexGenesisBlock = NULL;
int nBestHeight = -1; int nBestHeight = -1;
CBigNum bnBestChainWork = 0;
uint256 hashBestChain = 0; uint256 hashBestChain = 0;
CBlockIndex* pindexBest = NULL; CBlockIndex* pindexBest = NULL;
int64 nTimeBestReceived = 0; int64 nTimeBestReceived = 0;
@ -848,6 +849,23 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast)
return bnNew.GetCompact(); return bnNew.GetCompact();
} }
vector<int> 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->pprev = (*miPrev).second;
pindexNew->nHeight = pindexNew->pprev->nHeight + 1; pindexNew->nHeight = pindexNew->pprev->nHeight + 1;
} }
pindexNew->bnChainWork = (pindexNew->pprev ? pindexNew->pprev->bnChainWork : 0) + pindexNew->GetBlockWork();
CTxDB txdb; CTxDB txdb;
txdb.TxnBegin(); txdb.TxnBegin();
txdb.WriteBlockIndex(CDiskBlockIndex(pindexNew)); txdb.WriteBlockIndex(CDiskBlockIndex(pindexNew));
// New best // New best
if (pindexNew->nHeight > nBestHeight) if (pindexNew->bnChainWork > bnBestChainWork)
{ {
if (pindexGenesisBlock == NULL && hash == hashGenesisBlock) if (pindexGenesisBlock == NULL && hash == hashGenesisBlock)
{ {
@ -1253,6 +1272,7 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos)
hashBestChain = hash; hashBestChain = hash;
pindexBest = pindexNew; pindexBest = pindexNew;
nBestHeight = pindexBest->nHeight; nBestHeight = pindexBest->nHeight;
bnBestChainWork = pindexNew->bnChainWork;
nTimeBestReceived = GetTime(); nTimeBestReceived = GetTime();
nTransactionsUpdated++; nTransactionsUpdated++;
printf("AddToBlockIndex: new best=%s height=%d\n", hashBestChain.ToString().substr(0,16).c_str(), nBestHeight); 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); AddTimeData(pfrom->addr.ip, nTime);
AddStartingHeight(pfrom->nStartingHeight);
// Change version // Change version
if (pfrom->nVersion >= 209) if (pfrom->nVersion >= 209)
@ -2845,6 +2866,10 @@ int64 GetBalance()
} }
int GetRandInt(int nMax)
{
return GetRand(nMax);
}
bool SelectCoins(int64 nTargetValue, set<CWalletTx*>& setCoinsRet) bool SelectCoins(int64 nTargetValue, set<CWalletTx*>& setCoinsRet)
{ {
@ -2858,9 +2883,14 @@ bool SelectCoins(int64 nTargetValue, set<CWalletTx*>& setCoinsRet)
CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(cs_mapWallet)
{ {
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) vector<CWalletTx*> vCoins;
{ vCoins.reserve(mapWallet.size());
CWalletTx* pcoin = &(*it).second; for (map<uint256, CWalletTx>::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) if (!pcoin->IsFinal() || pcoin->fSpent)
continue; continue;
int64 n = pcoin->GetCredit(); int64 n = pcoin->GetCredit();

17
main.h

@ -32,6 +32,7 @@ extern map<uint256, CBlockIndex*> mapBlockIndex;
extern const uint256 hashGenesisBlock; extern const uint256 hashGenesisBlock;
extern CBlockIndex* pindexGenesisBlock; extern CBlockIndex* pindexGenesisBlock;
extern int nBestHeight; extern int nBestHeight;
extern CBigNum bnBestChainWork;
extern uint256 hashBestChain; extern uint256 hashBestChain;
extern CBlockIndex* pindexBest; extern CBlockIndex* pindexBest;
extern unsigned int nTransactionsUpdated; extern unsigned int nTransactionsUpdated;
@ -78,6 +79,7 @@ string SendMoneyToBitcoinAddress(string strAddress, int64 nValue, CWalletTx& wtx
void GenerateBitcoins(bool fGenerate); void GenerateBitcoins(bool fGenerate);
void ThreadBitcoinMiner(void* parg); void ThreadBitcoinMiner(void* parg);
void BitcoinMiner(); void BitcoinMiner();
bool IsInitialBlockDownload();
@ -986,11 +988,14 @@ public:
// Flush stdio buffers and commit to disk before returning // Flush stdio buffers and commit to disk before returning
fflush(fileout); fflush(fileout);
if (!IsInitialBlockDownload() || (nBestHeight+1) % 500 == 0)
{
#ifdef __WXMSW__ #ifdef __WXMSW__
_commit(_fileno(fileout)); _commit(_fileno(fileout));
#else #else
fsync(fileno(fileout)); fsync(fileno(fileout));
#endif #endif
}
return true; return true;
} }
@ -1072,6 +1077,7 @@ public:
unsigned int nFile; unsigned int nFile;
unsigned int nBlockPos; unsigned int nBlockPos;
int nHeight; int nHeight;
CBigNum bnChainWork;
// block header // block header
int nVersion; int nVersion;
@ -1089,6 +1095,7 @@ public:
nFile = 0; nFile = 0;
nBlockPos = 0; nBlockPos = 0;
nHeight = 0; nHeight = 0;
bnChainWork = 0;
nVersion = 0; nVersion = 0;
hashMerkleRoot = 0; hashMerkleRoot = 0;
@ -1105,6 +1112,7 @@ public:
nFile = nFileIn; nFile = nFileIn;
nBlockPos = nBlockPosIn; nBlockPos = nBlockPosIn;
nHeight = 0; nHeight = 0;
bnChainWork = 0;
nVersion = block.nVersion; nVersion = block.nVersion;
hashMerkleRoot = block.hashMerkleRoot; hashMerkleRoot = block.hashMerkleRoot;
@ -1118,6 +1126,11 @@ public:
return *phashBlock; return *phashBlock;
} }
CBigNum GetBlockWork() const
{
return (CBigNum(1)<<256) / (CBigNum().SetCompact(nBits)+1);
}
bool IsInMainChain() const bool IsInMainChain() const
{ {
return (pnext || this == pindexBest); return (pnext || this == pindexBest);

2
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 -l wxmsw29ud_html -l wxmsw29ud_core -l wxmsw29ud_adv -l wxbase29ud -l wxtiffd -l wxjpegd -l wxpngd -l wxzlibd
LIBS= \ 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 db_cxx \
-l eay32 \ -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 -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

1
makefile.osx vendored

@ -19,6 +19,7 @@ LIBS= -dead_strip \
$(DEPSDIR)/lib/libdb_cxx-4.8.a \ $(DEPSDIR)/lib/libdb_cxx-4.8.a \
$(DEPSDIR)/lib/libboost_system.a \ $(DEPSDIR)/lib/libboost_system.a \
$(DEPSDIR)/lib/libboost_filesystem.a \ $(DEPSDIR)/lib/libboost_filesystem.a \
$(DEPSDIR)/lib/libboost_program_options.a \
$(DEPSDIR)/lib/libcrypto.a $(DEPSDIR)/lib/libcrypto.a
WXDEFS=$(shell $(DEPSDIR)/bin/wx-config --cxxflags) -DNOPCH -DMSG_NOSIGNAL=0 WXDEFS=$(shell $(DEPSDIR)/bin/wx-config --cxxflags) -DNOPCH -DMSG_NOSIGNAL=0

2
makefile.unix

@ -21,7 +21,7 @@ WXLIBS= \
LIBS= \ LIBS= \
-Wl,-Bstatic \ -Wl,-Bstatic \
-l boost_system -l boost_filesystem \ -l boost_system -l boost_filesystem -l boost_program_options \
-l db_cxx \ -l db_cxx \
-l crypto \ -l crypto \
-Wl,-Bdynamic \ -Wl,-Bdynamic \

2
makefile.vc

@ -19,7 +19,7 @@ LIBPATHS= \
/LIBPATH:"/wxwidgets/lib/vc_lib" /LIBPATH:"/wxwidgets/lib/vc_lib"
LIBS= \ 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 \ libdb47sd.lib \
libeay32.lib \ libeay32.lib \
wxmsw29ud_html.lib wxmsw29ud_core.lib wxmsw29ud_adv.lib wxbase29ud.lib wxtiffd.lib wxjpegd.lib wxpngd.lib wxzlibd.lib \ wxmsw29ud_html.lib wxmsw29ud_core.lib wxmsw29ud_adv.lib wxbase29ud.lib wxtiffd.lib wxjpegd.lib wxpngd.lib wxzlibd.lib \

284
rpc.cpp

@ -21,7 +21,27 @@ void ThreadRPCServer2(void* parg);
typedef Value(*rpcfn_type)(const Array& params, bool fHelp); typedef Value(*rpcfn_type)(const Array& params, bool fHelp);
extern map<string, rpcfn_type> mapCallTable; extern map<string, rpcfn_type> 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) Value help(const Array& params, bool fHelp)
{ {
if (fHelp || params.size() != 0) if (fHelp || params.size() != 0)
throw runtime_error( throw runtime_error(
"help <pw>\n" "help\n"
"List commands."); "List commands.");
string strRet; string strRet;
@ -76,7 +95,7 @@ Value stop(const Array& params, bool fHelp)
{ {
if (fHelp || params.size() != 0) if (fHelp || params.size() != 0)
throw runtime_error( throw runtime_error(
"stop <pw>\n" "stop\n"
"Stop bitcoin server."); "Stop bitcoin server.");
// Shutdown will take long enough that the response should get back // 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) if (fHelp || params.size() != 0)
throw runtime_error( throw runtime_error(
"getblockcount <pw>\n" "getblockcount\n"
"Returns the number of blocks in the longest block chain."); "Returns the number of blocks in the longest block chain.");
return nBestHeight + 1; return nBestHeight + 1;
@ -100,7 +119,7 @@ Value getblocknumber(const Array& params, bool fHelp)
{ {
if (fHelp || params.size() != 0) if (fHelp || params.size() != 0)
throw runtime_error( throw runtime_error(
"getblocknumber <pw>\n" "getblocknumber\n"
"Returns the block number of the latest block in the longest block chain."); "Returns the block number of the latest block in the longest block chain.");
return nBestHeight; return nBestHeight;
@ -111,7 +130,7 @@ Value getconnectioncount(const Array& params, bool fHelp)
{ {
if (fHelp || params.size() != 0) if (fHelp || params.size() != 0)
throw runtime_error( throw runtime_error(
"getconnectioncount <pw>\n" "getconnectioncount\n"
"Returns the number of connections to other nodes."); "Returns the number of connections to other nodes.");
return (int)vNodes.size(); return (int)vNodes.size();
@ -134,7 +153,7 @@ Value getdifficulty(const Array& params, bool fHelp)
{ {
if (fHelp || params.size() != 0) if (fHelp || params.size() != 0)
throw runtime_error( throw runtime_error(
"getdifficulty <pw>\n" "getdifficulty\n"
"Returns the proof-of-work difficulty as a multiple of the minimum difficulty."); "Returns the proof-of-work difficulty as a multiple of the minimum difficulty.");
return GetDifficulty(); return GetDifficulty();
@ -145,7 +164,7 @@ Value getbalance(const Array& params, bool fHelp)
{ {
if (fHelp || params.size() != 0) if (fHelp || params.size() != 0)
throw runtime_error( throw runtime_error(
"getbalance <pw>\n" "getbalance\n"
"Returns the server's available balance."); "Returns the server's available balance.");
return ((double)GetBalance() / (double)COIN); return ((double)GetBalance() / (double)COIN);
@ -156,7 +175,7 @@ Value getgenerate(const Array& params, bool fHelp)
{ {
if (fHelp || params.size() != 0) if (fHelp || params.size() != 0)
throw runtime_error( throw runtime_error(
"getgenerate <pw>\n" "getgenerate\n"
"Returns true or false."); "Returns true or false.");
return (bool)fGenerateBitcoins; return (bool)fGenerateBitcoins;
@ -167,7 +186,7 @@ Value setgenerate(const Array& params, bool fHelp)
{ {
if (fHelp || params.size() < 1 || params.size() > 2) if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error( throw runtime_error(
"setgenerate <pw> <generate> [genproclimit]\n" "setgenerate <generate> [genproclimit]\n"
"<generate> is true or false to turn generation on or off.\n" "<generate> is true or false to turn generation on or off.\n"
"Generation is limited to [genproclimit] processors, -1 is unlimited."); "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) if (fHelp || params.size() != 0)
throw runtime_error( throw runtime_error(
"getinfo <pw>"); "getinfo");
Object obj; Object obj;
obj.push_back(Pair("balance", (double)GetBalance() / (double)COIN)); 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) if (fHelp || params.size() > 1)
throw runtime_error( throw runtime_error(
"getnewaddress <pw> [label]\n" "getnewaddress [label]\n"
"Returns a new bitcoin address for receiving payments. " "Returns a new bitcoin address for receiving payments. "
"If [label] is specified (recommended), it is added to the address book " "If [label] is specified (recommended), it is added to the address book "
"so payments received with the address will be labeled."); "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) if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error( throw runtime_error(
"setlabel <pw> <bitcoinaddress> <label>\n" "setlabel <bitcoinaddress> <label>\n"
"Sets the label associated with the given address."); "Sets the label associated with the given address.");
string strAddress = params[0].get_str(); string strAddress = params[0].get_str();
@ -250,7 +269,7 @@ Value getlabel(const Array& params, bool fHelp)
{ {
if (fHelp || params.size() != 1) if (fHelp || params.size() != 1)
throw runtime_error( throw runtime_error(
"getlabel <pw> <bitcoinaddress>\n" "getlabel <bitcoinaddress>\n"
"Returns the label associated with the given address."); "Returns the label associated with the given address.");
string strAddress = params[0].get_str(); string strAddress = params[0].get_str();
@ -270,7 +289,7 @@ Value getaddressesbylabel(const Array& params, bool fHelp)
{ {
if (fHelp || params.size() != 1) if (fHelp || params.size() != 1)
throw runtime_error( throw runtime_error(
"getaddressesbylabel <pw> <label>\n" "getaddressesbylabel <label>\n"
"Returns the list of addresses with the given label."); "Returns the list of addresses with the given label.");
string strLabel = params[0].get_str(); string strLabel = params[0].get_str();
@ -300,7 +319,7 @@ Value sendtoaddress(const Array& params, bool fHelp)
{ {
if (fHelp || params.size() < 2 || params.size() > 4) if (fHelp || params.size() < 2 || params.size() > 4)
throw runtime_error( throw runtime_error(
"sendtoaddress <pw> <bitcoinaddress> <amount> [comment] [comment-to]\n" "sendtoaddress <bitcoinaddress> <amount> [comment] [comment-to]\n"
"<amount> is a real and is rounded to the nearest 0.01"); "<amount> is a real and is rounded to the nearest 0.01");
string strAddress = params[0].get_str(); string strAddress = params[0].get_str();
@ -328,7 +347,7 @@ Value listtransactions(const Array& params, bool fHelp)
{ {
if (fHelp || params.size() > 2) if (fHelp || params.size() > 2)
throw runtime_error( throw runtime_error(
"listtransactions <pw> [count=10] [includegenerated=false]\n" "listtransactions [count=10] [includegenerated=false]\n"
"Returns up to [count] most recent transactions."); "Returns up to [count] most recent transactions.");
int64 nCount = 10; int64 nCount = 10;
@ -349,7 +368,7 @@ Value getreceivedbyaddress(const Array& params, bool fHelp)
{ {
if (fHelp || params.size() < 1 || params.size() > 2) if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error( throw runtime_error(
"getreceivedbyaddress <pw> <bitcoinaddress> [minconf=1]\n" "getreceivedbyaddress <bitcoinaddress> [minconf=1]\n"
"Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations."); "Returns the total amount received by <bitcoinaddress> in transactions with at least [minconf] confirmations.");
// Bitcoin address // Bitcoin address
@ -390,7 +409,7 @@ Value getreceivedbylabel(const Array& params, bool fHelp)
{ {
if (fHelp || params.size() < 1 || params.size() > 2) if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error( throw runtime_error(
"getreceivedbylabel <pw> <label> [minconf=1]\n" "getreceivedbylabel <label> [minconf=1]\n"
"Returns the total amount received by addresses with <label> in transactions with at least [minconf] confirmations."); "Returns the total amount received by addresses with <label> in transactions with at least [minconf] confirmations.");
// Get the set of pub keys that have the label // Get the set of pub keys that have the label
@ -553,7 +572,7 @@ Value listreceivedbyaddress(const Array& params, bool fHelp)
{ {
if (fHelp || params.size() > 2) if (fHelp || params.size() > 2)
throw runtime_error( throw runtime_error(
"listreceivedbyaddress <pw> [minconf=1] [includeempty=false]\n" "listreceivedbyaddress [minconf=1] [includeempty=false]\n"
"[minconf] is the minimum number of confirmations before payments are included.\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" "[includeempty] whether to include addresses that haven't received any payments.\n"
"Returns an array of objects containing:\n" "Returns an array of objects containing:\n"
@ -569,7 +588,7 @@ Value listreceivedbylabel(const Array& params, bool fHelp)
{ {
if (fHelp || params.size() > 2) if (fHelp || params.size() > 2)
throw runtime_error( throw runtime_error(
"listreceivedbylabel <pw> [minconf=1] [includeempty=false]\n" "listreceivedbylabel [minconf=1] [includeempty=false]\n"
"[minconf] is the minimum number of confirmations before payments are included.\n" "[minconf] is the minimum number of confirmations before payments are included.\n"
"[includeempty] whether to include labels that haven't received any payments.\n" "[includeempty] whether to include labels that haven't received any payments.\n"
"Returns an array of objects containing:\n" "Returns an array of objects containing:\n"
@ -632,23 +651,41 @@ map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)
// and to be compatible with other JSON-RPC implementations. // and to be compatible with other JSON-RPC implementations.
// //
string HTTPPost(const string& strMsg) string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
{ {
return strprintf( ostringstream s;
"POST / HTTP/1.1\r\n" s << "POST / HTTP/1.1\r\n"
"User-Agent: json-rpc/1.0\r\n" << "User-Agent: json-rpc/1.0\r\n"
"Host: 127.0.0.1\r\n" << "Host: 127.0.0.1\r\n"
"Content-Type: application/json\r\n" << "Content-Type: application/json\r\n"
"Content-Length: %d\r\n" << "Content-Length: " << strMsg.size() << "\r\n"
"Accept: application/json\r\n" << "Accept: application/json\r\n";
"\r\n" for (map<string,string>::const_iterator it = mapRequestHeaders.begin(); it != mapRequestHeaders.end(); ++it)
"%s", s << it->first << ": " << it->second << "\r\n";
strMsg.size(), s << "\r\n" << strMsg;
strMsg.c_str());
return s.str();
} }
string HTTPReply(const string& strMsg, int nStatus=200) string HTTPReply(const string& strMsg, int nStatus=200)
{ {
if (nStatus == 401)
return "HTTP/1.0 401 Authorization Required\r\n"
"Server: HTTPd/1.0\r\n"
"Date: Sat, 08 Jul 2006 12:04:08 GMT\r\n"
"WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
"Content-Type: text/html\r\n"
"Content-Length: 311\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";
string strStatus; string strStatus;
if (nStatus == 200) strStatus = "OK"; if (nStatus == 200) strStatus = "OK";
if (nStatus == 500) strStatus = "Internal Server Error"; if (nStatus == 500) strStatus = "Internal Server Error";
@ -667,7 +704,17 @@ string HTTPReply(const string& strMsg, int nStatus=200)
strMsg.c_str()); strMsg.c_str());
} }
int ReadHTTPHeader(tcp::iostream& stream) int ReadHTTPStatus(tcp::iostream& stream)
{
string str;
getline(stream, str);
vector<string> vWords;
boost::split(vWords, str, boost::is_any_of(" "));
int nStatus = atoi(vWords[1].c_str());
return nStatus;
}
int ReadHTTPHeader(tcp::iostream& stream, map<string, string>& mapHeadersRet)
{ {
int nLen = 0; int nLen = 0;
loop loop
@ -676,26 +723,92 @@ int ReadHTTPHeader(tcp::iostream& stream)
std::getline(stream, str); std::getline(stream, str);
if (str.empty() || str == "\r") if (str.empty() || str == "\r")
break; break;
if (str.substr(0,15) == "Content-Length:") string::size_type nColon = str.find(":");
nLen = atoi(str.substr(15)); if (nColon != string::npos)
{
string strHeader = str.substr(0, nColon);
boost::trim(strHeader);
string strValue = str.substr(nColon+1);
boost::trim(strValue);
mapHeadersRet[strHeader] = strValue;
if (strHeader == "Content-Length")
nLen = atoi(strValue.c_str());
}
} }
return nLen; return nLen;
} }
inline string ReadHTTP(tcp::iostream& stream) int ReadHTTP(tcp::iostream& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
{ {
mapHeadersRet.clear();
strMessageRet = "";
// Read status
int nStatus = ReadHTTPStatus(stream);
// Read header // Read header
int nLen = ReadHTTPHeader(stream); int nLen = ReadHTTPHeader(stream, mapHeadersRet);
if (nLen <= 0) if (nLen <= 0)
return string(); return 500;
// Read message // Read message
vector<char> vch(nLen); vector<char> vch(nLen);
stream.read(&vch[0], nLen); stream.read(&vch[0], nLen);
return string(vch.begin(), vch.end()); strMessageRet = string(vch.begin(), vch.end());
return nStatus;
} }
string EncodeBase64(string s)
{
BIO *b64, *bmem;
BUF_MEM *bptr;
b64 = BIO_new(BIO_f_base64());
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-1);
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 // JSON-RPC protocol
@ -751,15 +864,20 @@ void ThreadRPCServer2(void* parg)
{ {
printf("ThreadRPCServer started\n"); printf("ThreadRPCServer started\n");
if (mapArgs.count("-rpcpw")) if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
strRPCPassword = mapArgs["-rpcpw"];
if (strRPCPassword == "")
{ {
#if defined(__WXMSW__) && wxUSE_GUI string strWhatAmI = "To use bitcoind";
MyMessageBox("Warning: rpc password is blank, use -rpcpw=<password>\n", "Bitcoin", wxOK | wxICON_EXCLAMATION); if (mapArgs.count("-server"))
#else strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
fprintf(stdout, "Warning: rpc password is blank, use -rpcpw=<password>\n"); else if (mapArgs.count("-daemon"))
#endif 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;
} }
// Bind to loopback 127.0.0.1 so the socket can only be accessed locally // Bind to loopback 127.0.0.1 so the socket can only be accessed locally
@ -783,7 +901,26 @@ void ThreadRPCServer2(void* parg)
continue; continue;
// Receive request // Receive request
string strRequest = ReadHTTP(stream); map<string, string> mapHeaders;
string strRequest;
ReadHTTP(stream, mapHeaders, strRequest);
// 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;
}
// Handle multiple invocations per request // Handle multiple invocations per request
string::iterator begin = strRequest.begin(); string::iterator begin = strRequest.begin();
@ -808,23 +945,11 @@ void ThreadRPCServer2(void* parg)
printf("ThreadRPCServer method=%s\n", strMethod.c_str()); printf("ThreadRPCServer method=%s\n", strMethod.c_str());
// Check password
if (params.size() < 1 || params[0].type() != str_type)
throw runtime_error("First parameter must be the password.");
if (params[0].get_str() != strRPCPassword)
{
if (strRPCPassword.size() < 15)
Sleep(50);
begin = strRequest.end();
printf("ThreadRPCServer incorrect password attempt\n");
throw runtime_error("Incorrect password.");
}
// Execute // Execute
map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod); map<string, rpcfn_type>::iterator mi = mapCallTable.find(strMethod);
if (mi == mapCallTable.end()) if (mi == mapCallTable.end())
throw runtime_error("Method not found."); throw runtime_error("Method not found.");
Value result = (*(*mi).second)(Array(params.begin()+1, params.end()), false); Value result = (*(*mi).second)(params, false);
// Send reply // Send reply
string strReply = JSONRPCReply(result, Value::null, id); string strReply = JSONRPCReply(result, Value::null, id);
@ -847,18 +972,36 @@ void ThreadRPCServer2(void* parg)
Value CallRPC(const string& strMethod, const Array& params) Value 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 // Connect to localhost
tcp::iostream stream("127.0.0.1", "8332"); tcp::iostream stream("127.0.0.1", "8332");
if (stream.fail()) if (stream.fail())
throw runtime_error("couldn't connect to server"); throw runtime_error("couldn't connect to server");
// HTTP basic authentication
string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
map<string, string> mapRequestHeaders;
mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
// Send request // Send request
string strRequest = JSONRPCRequest(strMethod, params, 1); string strRequest = JSONRPCRequest(strMethod, params, 1);
stream << HTTPPost(strRequest) << std::flush; string strPost = HTTPPost(strRequest, mapRequestHeaders);
stream << strPost << std::flush;
// Receive reply // Receive reply
string strReply = ReadHTTP(stream); map<string, string> mapHeaders;
if (strReply.empty()) 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 != 500)
throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
else if (strReply.empty())
throw runtime_error("no response from server"); throw runtime_error("no response from server");
// Parse reply // Parse reply
@ -904,7 +1047,14 @@ int CommandLineRPC(int argc, char *argv[])
{ {
try try
{ {
// Check that method exists // Skip switches
while (argc > 1 && IsSwitchChar(argv[1][0]))
{
argc--;
argv++;
}
// Check that the method exists
if (argc < 2) if (argc < 2)
throw runtime_error("too few parameters"); throw runtime_error("too few parameters");
string strMethod = argv[1]; string strMethod = argv[1];

4
serialize.h

@ -19,8 +19,8 @@ class CScript;
class CDataStream; class CDataStream;
class CAutoFile; class CAutoFile;
static const int VERSION = 302; static const int VERSION = 303;
static const char* pszSubVer = ".2"; static const char* pszSubVer = "";

6
setup.nsi

@ -7,7 +7,7 @@ RequestExecutionLevel highest
# General Symbol Definitions # General Symbol Definitions
!define REGKEY "SOFTWARE\$(^Name)" !define REGKEY "SOFTWARE\$(^Name)"
!define VERSION 0.3.2 !define VERSION 0.3.3
!define COMPANY "Bitcoin project" !define COMPANY "Bitcoin project"
!define URL http://www.bitcoin.org/ !define URL http://www.bitcoin.org/
@ -42,12 +42,12 @@ Var StartMenuGroup
!insertmacro MUI_LANGUAGE English !insertmacro MUI_LANGUAGE English
# Installer attributes # Installer attributes
OutFile bitcoin-0.3.2-win32-setup.exe OutFile bitcoin-0.3.3-win32-setup.exe
InstallDir $PROGRAMFILES\Bitcoin InstallDir $PROGRAMFILES\Bitcoin
CRCCheck on CRCCheck on
XPStyle on XPStyle on
ShowInstDetails show ShowInstDetails show
VIProductVersion 0.3.2.0 VIProductVersion 0.3.3.0
VIAddVersionKey ProductName Bitcoin VIAddVersionKey ProductName Bitcoin
VIAddVersionKey ProductVersion "${VERSION}" VIAddVersionKey ProductVersion "${VERSION}"
VIAddVersionKey CompanyName "${COMPANY}" VIAddVersionKey CompanyName "${COMPANY}"

1
ui.cpp

@ -1614,6 +1614,7 @@ void COptionsDialog::OnButtonApply(wxCommandEvent& event)
CAboutDialog::CAboutDialog(wxWindow* parent) : CAboutDialogBase(parent) CAboutDialog::CAboutDialog(wxWindow* parent) : CAboutDialogBase(parent)
{ {
m_staticTextVersion->SetLabel(strprintf(_("version %d.%d.%d beta"), VERSION/10000, (VERSION/100)%100, VERSION%100)); m_staticTextVersion->SetLabel(strprintf(_("version %d.%d.%d beta"), VERSION/10000, (VERSION/100)%100, VERSION%100));
//m_staticTextVersion->SetLabel(strprintf(_("version %d.%d.%d%s beta"), VERSION/10000, (VERSION/100)%100, VERSION%100, pszSubVer));
// Change (c) into UTF-8 or ANSI copyright symbol // Change (c) into UTF-8 or ANSI copyright symbol
wxString str = m_staticTextMain->GetLabel(); wxString str = m_staticTextMain->GetLabel();

2
uibase.h

@ -227,7 +227,7 @@ class CAboutDialogBase : public wxDialog
public: public:
wxStaticText* m_staticTextVersion; wxStaticText* m_staticTextVersion;
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 ); 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 );
~CAboutDialogBase(); ~CAboutDialogBase();
}; };

2
uiproject.fbp

@ -2866,7 +2866,7 @@
<property name="minimum_size"></property> <property name="minimum_size"></property>
<property name="name">CAboutDialogBase</property> <property name="name">CAboutDialogBase</property>
<property name="pos"></property> <property name="pos"></property>
<property name="size">532,329</property> <property name="size">532,333</property>
<property name="style">wxDEFAULT_DIALOG_STYLE</property> <property name="style">wxDEFAULT_DIALOG_STYLE</property>
<property name="subclass"></property> <property name="subclass"></property>
<property name="title">About Bitcoin</property> <property name="title">About Bitcoin</property>

41
util.cpp

@ -416,7 +416,7 @@ void ParseParameters(int argc, char* argv[])
{ {
mapArgs.clear(); mapArgs.clear();
mapMultiArgs.clear(); mapMultiArgs.clear();
for (int i = 0; i < argc; i++) for (int i = 1; i < argc; i++)
{ {
char psz[10000]; char psz[10000];
strlcpy(psz, argv[i], sizeof(psz)); strlcpy(psz, argv[i], sizeof(psz));
@ -431,6 +431,8 @@ void ParseParameters(int argc, char* argv[])
if (psz[0] == '/') if (psz[0] == '/')
psz[0] = '-'; psz[0] = '-';
#endif #endif
if (psz[0] != '-')
break;
mapArgs[psz] = pszValue; mapArgs[psz] = pszValue;
mapMultiArgs[psz].push_back(pszValue); mapMultiArgs[psz].push_back(pszValue);
} }
@ -619,6 +621,38 @@ string GetDataDir()
return pszDir; return pszDir;
} }
string GetConfigFile()
{
namespace fs = boost::filesystem;
fs::path pathConfig(mapArgs.count("-conf") ? mapArgs["-conf"] : string("bitcoin.conf"));
if (!pathConfig.is_complete())
pathConfig = fs::path(GetDataDir()) / pathConfig;
return pathConfig.string();
}
void ReadConfigFile(map<string, string>& mapSettingsRet,
map<string, vector<string> >& mapMultiSettingsRet)
{
namespace fs = boost::filesystem;
namespace pod = boost::program_options::detail;
fs::ifstream streamConfig(GetConfigFile());
if (!streamConfig.good())
return;
set<string> setOptions;
setOptions.insert("*");
for (pod::config_file_iterator it(streamConfig, setOptions), end; it != end; ++it)
{
// Don't overwrite existing settings so command line settings override bitcoin.conf
string strKey = string("-") + it->string_key;
if (mapSettingsRet.count(strKey) == 0)
mapSettingsRet[strKey] = it->value[0];
mapMultiSettingsRet[strKey].push_back(it->value[0]);
}
}
int GetFilesize(FILE* file) int GetFilesize(FILE* file)
{ {
int nSavePos = ftell(file); int nSavePos = ftell(file);
@ -656,9 +690,6 @@ void ShrinkDebugFile()
// //
// "Never go to sea with two chronometers; take one or three." // "Never go to sea with two chronometers; take one or three."
// Our three chronometers are: // Our three chronometers are:
@ -701,7 +732,7 @@ void AddTimeData(unsigned int ip, int64 nTime)
sort(vTimeOffsets.begin(), vTimeOffsets.end()); sort(vTimeOffsets.begin(), vTimeOffsets.end());
int64 nMedian = vTimeOffsets[vTimeOffsets.size()/2]; int64 nMedian = vTimeOffsets[vTimeOffsets.size()/2];
nTimeOffset = nMedian; nTimeOffset = nMedian;
if ((nMedian > 0 ? nMedian : -nMedian) > 36 * 60 * 60) if ((nMedian > 0 ? nMedian : -nMedian) > 70 * 60)
{ {
// Only let other nodes change our clock so far before we // Only let other nodes change our clock so far before we
// go to the NTP servers // go to the NTP servers

11
util.h

@ -141,6 +141,8 @@ void ParseParameters(int argc, char* argv[]);
const char* wxGetTranslation(const char* psz); const char* wxGetTranslation(const char* psz);
int GetFilesize(FILE* file); int GetFilesize(FILE* file);
void GetDataDir(char* pszDirRet); void GetDataDir(char* pszDirRet);
string GetConfigFile();
void ReadConfigFile(map<string, string>& mapSettingsRet, map<string, vector<string> >& mapMultiSettingsRet);
#ifdef __WXMSW__ #ifdef __WXMSW__
string MyGetSpecialFolderPath(int nFolder, bool fCreate); string MyGetSpecialFolderPath(int nFolder, bool fCreate);
#endif #endif
@ -348,7 +350,14 @@ void skipspaces(T& it)
++it; ++it;
} }
inline bool IsSwitchChar(char c)
{
#ifdef __WXMSW__
return c == '-' || c == '/';
#else
return c == '-';
#endif
}

Loading…
Cancel
Save