diff --git a/build.txt b/build.txt index 67b03fe24..4368af855 100644 --- a/build.txt +++ b/build.txt @@ -10,7 +10,7 @@ cryptographic software written by Eric Young (eay@cryptsoft.com). Compilers Supported ------------------- -MinGW GCC +MinGW GCC (v3.4.5) Microsoft Visual C++ 6.0 SP6 diff --git a/db.cpp b/db.cpp index 699a94f2e..f9e25834d 100644 --- a/db.cpp +++ b/db.cpp @@ -61,18 +61,19 @@ CDB::CDB(const char* pszFile, const char* pszMode, bool fTxn) : pdb(NULL) { if (fShutdown) return; - string strAppDir = GetAppDir(); - string strLogDir = strAppDir + "\\database"; + string strDataDir = GetDataDir(); + string strLogDir = strDataDir + "\\database"; _mkdir(strLogDir.c_str()); - printf("dbenv.open strAppDir=%s\n", strAppDir.c_str()); + string strErrorFile = strDataDir + "\\db.log"; + printf("dbenv.open strLogDir=%s strErrorFile=%s\n", strLogDir.c_str(), strErrorFile.c_str()); dbenv.set_lg_dir(strLogDir.c_str()); dbenv.set_lg_max(10000000); dbenv.set_lk_max_locks(10000); dbenv.set_lk_max_objects(10000); - dbenv.set_errfile(fopen("db.log", "a")); /// debug + dbenv.set_errfile(fopen(strErrorFile.c_str(), "a")); /// debug ///dbenv.log_set_config(DB_LOG_AUTO_REMOVE, 1); /// causes corruption - ret = dbenv.open(strAppDir.c_str(), + ret = dbenv.open(strDataDir.c_str(), DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | @@ -139,6 +140,8 @@ void DBFlush(bool fShutdown) // Flush log data to the actual data file // on all files that are not in use printf("DBFlush(%s)\n", fShutdown ? "true" : "false"); + if (!fDbEnvInit) + return; CRITICAL_BLOCK(cs_db) { dbenv.txn_checkpoint(0, 0, 0); @@ -421,7 +424,7 @@ bool CAddrDB::LoadAddresses() while (fgets(psz, sizeof(psz), filein)) { CAddress addr(psz, NODE_NETWORK); - if (addr.ip != 0) + if (addr.IsValid()) { AddAddress(*this, addr); mapIRCAddresses.insert(make_pair(addr.GetKey(), addr)); @@ -676,10 +679,10 @@ void ThreadFlushWalletDB(void* parg) { // Flush wallet.dat so it's self contained nLastFlushed == nWalletDBUpdated; - int64 nStart = PerformanceCounter(); + int64 nStart = GetTimeMillis(); dbenv.txn_checkpoint(0, 0, 0); dbenv.lsn_reset(strFile.c_str(), 0); - printf("Flushed wallet.dat %15"PRI64d"\n", PerformanceCounter() - nStart); + printf("Flushed wallet.dat %"PRI64d"ms\n", GetTimeMillis() - nStart); mapFileUseCount.erase(mi++); } } diff --git a/irc.cpp b/irc.cpp index 707b4fe19..f839dc522 100644 --- a/irc.cpp +++ b/irc.cpp @@ -40,7 +40,7 @@ bool DecodeAddress(string str, CAddress& addr) return false; memcpy(&tmp, &vch[0], sizeof(tmp)); - addr = CAddress(tmp.ip, tmp.port); + addr = CAddress(tmp.ip, tmp.port, NODE_NETWORK); return true; } @@ -163,6 +163,7 @@ void ThreadIRCSeed(void* parg) int nErrorWait = 10; int nRetryWait = 10; + // IRC server blocks TOR users if (fUseProxy && addrProxy.port == htons(9050)) return; @@ -237,14 +238,14 @@ void ThreadIRCSeed(void* parg) { // index 7 is limited to 16 characters // could get full length name at index 10, but would be different from join messages - strcpy(pszName, vWords[7].c_str()); + strlcpy(pszName, vWords[7].c_str(), sizeof(pszName)); printf("IRC got who\n"); } if (vWords[1] == "JOIN" && vWords[0].size() > 1) { // :username!username@50000007.F000000B.90000002.IP JOIN :#channelname - strcpy(pszName, vWords[0].c_str() + 1); + strlcpy(pszName, vWords[0].c_str() + 1, sizeof(pszName)); if (strchr(pszName, '!')) *strchr(pszName, '!') = '\0'; printf("IRC got join\n"); diff --git a/irc.h b/irc.h index 1dc348a8b..91c3ffe68 100644 --- a/irc.h +++ b/irc.h @@ -1,11 +1,6 @@ // Copyright (c) 2009 Satoshi Nakamoto // Distributed under the MIT/X11 software license, see the accompanying // file license.txt or http://www.opensource.org/licenses/mit-license.php. - -#ifndef __WXMSW__ -#define closesocket(s) close(s) -typedef u_int SOCKET; -#endif extern bool RecvLine(SOCKET hSocket, string& strLine); extern void ThreadIRCSeed(void* parg); diff --git a/main.cpp b/main.cpp index 156267771..ade3b51c7 100644 --- a/main.cpp +++ b/main.cpp @@ -42,7 +42,6 @@ map > mapPubKeys; CCriticalSection cs_mapKeys; CKey keyUser; -string strSetDataDir; int nDropMessagesTest = 0; // Settings @@ -1361,52 +1360,17 @@ bool ScanMessageStart(Stream& s) } } -string GetAppDir() -{ - string strDir; - if (!strSetDataDir.empty()) - { - strDir = strSetDataDir; - } - else if (getenv("APPDATA")) - { - strDir = strprintf("%s\\Bitcoin", getenv("APPDATA")); - } - else if (getenv("USERPROFILE")) - { - string strAppData = strprintf("%s\\Application Data", getenv("USERPROFILE")); - static bool fMkdirDone; - if (!fMkdirDone) - { - fMkdirDone = true; - _mkdir(strAppData.c_str()); - } - strDir = strprintf("%s\\Bitcoin", strAppData.c_str()); - } - else - { - return "."; - } - static bool fMkdirDone; - if (!fMkdirDone) - { - fMkdirDone = true; - _mkdir(strDir.c_str()); - } - return strDir; -} - bool CheckDiskSpace(int64 nAdditionalBytes) { wxLongLong nFreeBytesAvailable = 0; - if (!wxGetDiskSpace(wxStandardPaths::Get().GetDataDir(), NULL, &nFreeBytesAvailable)) + if (!wxGetDiskSpace(GetDataDir(), NULL, &nFreeBytesAvailable)) { printf("ERROR: wxGetDiskSpace() failed\n"); return true; } // Check for 15MB because database could create another 10MB log file at any time - if (nFreeBytesAvailable < (int64)15000000 + nAdditionalBytes) + if (nFreeBytesAvailable.GetValue() < (int64)15000000 + nAdditionalBytes) { fShutdown = true; wxMessageBox("Warning: Your disk space is low ", "Bitcoin", wxICON_EXCLAMATION); @@ -1420,7 +1384,7 @@ FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszM { if (nFile == -1) return NULL; - FILE* file = fopen(strprintf("%s\\blk%04d.dat", GetAppDir().c_str(), nFile).c_str(), pszMode); + FILE* file = fopen(strprintf("%s\\blk%04d.dat", GetDataDir().c_str(), nFile).c_str(), pszMode); if (!file) return NULL; if (nBlockPos != 0 && !strchr(pszMode, 'a') && !strchr(pszMode, 'w')) @@ -1719,7 +1683,7 @@ bool ProcessMessages(CNode* pfrom) if (strstr(e.what(), "CDataStream::read() : end of data")) { // Allow exceptions from underlength message on vRecv - LogException(&e, "ProcessMessage()"); + printf("ProcessMessage(%s, %d bytes) : Exception '%s' caught, normally caused by a message being shorter than its stated length\n", strCommand.c_str(), nMessageSize, e.what()); } else PrintException(&e, "ProcessMessage()"); @@ -2512,7 +2476,7 @@ bool BitcoinMiner() int64 GetBalance() { - int64 nStart = PerformanceCounter(); + int64 nStart = GetTimeMillis(); int64 nTotal = 0; CRITICAL_BLOCK(cs_mapWallet) @@ -2522,11 +2486,11 @@ int64 GetBalance() CWalletTx* pcoin = &(*it).second; if (!pcoin->IsFinal() || pcoin->fSpent) continue; - nTotal += pcoin->GetCredit(); + nTotal += pcoin->GetCredit(true); } } - ///printf(" GetBalance() time = %15"PRI64d"\n", PerformanceCounter() - nStart); + //printf("GetBalance() %"PRI64d"ms\n", GetTimeMillis() - nStart); return nTotal; } diff --git a/main.h b/main.h index fcfd33d13..a0258cf2c 100644 --- a/main.h +++ b/main.h @@ -34,7 +34,6 @@ extern int nBestHeight; extern uint256 hashBestChain; extern CBlockIndex* pindexBest; extern unsigned int nTransactionsUpdated; -extern string strSetDataDir; extern int nDropMessagesTest; // Settings @@ -50,7 +49,6 @@ extern int nLimitProcessors; -string GetAppDir(); bool CheckDiskSpace(int64 nAdditionalBytes=0); FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszMode="rb"); FILE* AppendBlockFile(unsigned int& nFileRet); @@ -405,10 +403,10 @@ public: { // Time based nLockTime implemented in 0.1.6, // do not use time based until most 0.1.5 nodes have upgraded. - if (nBlockTime == 0) - nBlockTime = GetAdjustedTime(); if (nLockTime == 0) return true; + if (nBlockTime == 0) + nBlockTime = GetAdjustedTime(); if (nLockTime < (nLockTime < 500000000 ? nBestHeight : nBlockTime)) return true; foreach(const CTxIn& txin, vin) @@ -627,6 +625,8 @@ public: // memory only mutable bool fMerkleVerified; + mutable bool fGetCreditCached; + mutable int64 nGetCreditCached; CMerkleTx() @@ -644,14 +644,22 @@ public: hashBlock = 0; nIndex = -1; fMerkleVerified = false; + fGetCreditCached = false; + nGetCreditCached = 0; } - int64 GetCredit() const + int64 GetCredit(bool fUseCache=false) const { // Must wait until coinbase is safely deep enough in the chain before valuing it if (IsCoinBase() && GetBlocksToMaturity() > 0) return 0; - return CTransaction::GetCredit(); + + // GetBalance can assume transactions in mapWallet won't change + if (fUseCache && fGetCreditCached) + return nGetCreditCached; + nGetCreditCached = CTransaction::GetCredit(); + fGetCreditCached = true; + return nGetCreditCached; } IMPLEMENT_SERIALIZE diff --git a/net.cpp b/net.cpp index 22b84f9de..8ccf48b81 100644 --- a/net.cpp +++ b/net.cpp @@ -21,8 +21,7 @@ bool OpenNetworkConnection(const CAddress& addrConnect); bool fClient = false; uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK); CAddress addrLocalHost(0, DEFAULT_PORT, nLocalServices); -CNode nodeLocalHost(INVALID_SOCKET, CAddress("127.0.0.1", nLocalServices)); -CNode* pnodeLocalHost = &nodeLocalHost; +CNode* pnodeLocalHost = NULL; uint64 nLocalHostNonce = 0; bool fShutdown = false; array vnThreadsRunning; @@ -129,7 +128,7 @@ bool GetMyExternalIP2(const CAddress& addrConnect, const char* pszGet, const cha strLine = wxString(strLine).Trim(); CAddress addr(strLine.c_str()); printf("GetMyExternalIP() received [%s] %s\n", strLine.c_str(), addr.ToString().c_str()); - if (addr.ip == 0 || !addr.IsRoutable()) + if (addr.ip == 0 || addr.ip == INADDR_NONE || !addr.IsRoutable()) return false; ipRet = addr.ip; return true; @@ -740,10 +739,29 @@ void ThreadOpenConnections2(void* parg) printf("ThreadOpenConnections started\n"); // Connect to one specified address - while (mapArgs.count("/connect")) + while (mapArgs.count("-connect")) { - OpenNetworkConnection(CAddress(mapArgs["/connect"].c_str())); - Sleep(10000); + OpenNetworkConnection(CAddress(mapArgs["-connect"])); + for (int i = 0; i < 10; i++) + { + Sleep(1000); + CheckForShutdown(1); + } + } + + // Connect to manually added nodes first + if (mapArgs.count("-addnode")) + { + foreach(string strAddr, mapMultiArgs["-addnode"]) + { + CAddress addr(strAddr, NODE_NETWORK); + if (addr.IsValid()) + { + OpenNetworkConnection(addr); + Sleep(1000); + CheckForShutdown(1); + } + } } // Initiate network connections @@ -967,6 +985,8 @@ void ThreadMessageHandler2(void* parg) bool StartNode(string& strError) { + if (pnodeLocalHost == NULL) + pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress("127.0.0.1", nLocalServices)); strError = ""; // Sockets startup @@ -1031,7 +1051,7 @@ bool StartNode(string& strError) printf("%s\n", strError.c_str()); return false; } - printf("bound to addrLocalHost = %s\n\n", addrLocalHost.ToString().c_str()); + printf("bound to addrLocalHost = %s\n", addrLocalHost.ToString().c_str()); // Listen for incoming connections if (listen(hListenSocket, SOMAXCONN) == SOCKET_ERROR) diff --git a/net.h b/net.h index 2eece2c06..7716426f0 100644 --- a/net.h +++ b/net.h @@ -1,12 +1,6 @@ // Copyright (c) 2009 Satoshi Nakamoto // Distributed under the MIT/X11 software license, see the accompanying // file license.txt or http://www.opensource.org/licenses/mit-license.php. - -#ifndef __WXMSW__ -#define closesocket(s) close(s) -#define INVALID_SOCKET (SOCKET)(~0) -typedef u_int SOCKET; -#endif class CMessageHeader; class CAddress; @@ -148,61 +142,73 @@ public: CAddress() { - nServices = 0; - memcpy(pchReserved, pchIPv4, sizeof(pchReserved)); - ip = 0; - port = DEFAULT_PORT; - nTime = GetAdjustedTime(); - nLastFailed = 0; + Init(); } - CAddress(unsigned int ipIn, unsigned short portIn=DEFAULT_PORT, uint64 nServicesIn=0) + CAddress(unsigned int ipIn, unsigned short portIn=DEFAULT_PORT, uint64 nServicesIn=NODE_NETWORK) { - nServices = nServicesIn; - memcpy(pchReserved, pchIPv4, sizeof(pchReserved)); + Init(); ip = ipIn; port = portIn; - nTime = GetAdjustedTime(); - nLastFailed = 0; + nServices = nServicesIn; } - explicit CAddress(const struct sockaddr_in& sockaddr, uint64 nServicesIn=0) + explicit CAddress(const struct sockaddr_in& sockaddr, uint64 nServicesIn=NODE_NETWORK) { - nServices = nServicesIn; - memcpy(pchReserved, pchIPv4, sizeof(pchReserved)); + Init(); ip = sockaddr.sin_addr.s_addr; port = sockaddr.sin_port; - nTime = GetAdjustedTime(); - nLastFailed = 0; + nServices = nServicesIn; } - explicit CAddress(const char* pszIn, uint64 nServicesIn=0) + explicit CAddress(const char* pszIn, uint64 nServicesIn=NODE_NETWORK) { + Init(); + SetAddress(pszIn); nServices = nServicesIn; + } + + explicit CAddress(string strIn, uint64 nServicesIn=NODE_NETWORK) + { + Init(); + SetAddress(strIn.c_str()); + nServices = nServicesIn; + } + + void Init() + { + nServices = NODE_NETWORK; memcpy(pchReserved, pchIPv4, sizeof(pchReserved)); ip = INADDR_NONE; port = DEFAULT_PORT; nTime = GetAdjustedTime(); nLastFailed = 0; + } + bool SetAddress(const char* pszIn) + { + ip = INADDR_NONE; + port = DEFAULT_PORT; char psz[100]; - if (strlen(pszIn) > ARRAYLEN(psz)-1) - return; - strcpy(psz, pszIn); + strlcpy(psz, pszIn, sizeof(psz)); unsigned int a=0, b=0, c=0, d=0, e=0; if (sscanf(psz, "%u.%u.%u.%u:%u", &a, &b, &c, &d, &e) < 4) - return; + return false; char* pszPort = strchr(psz, ':'); if (pszPort) { *pszPort++ = '\0'; port = htons(atoi(pszPort)); - if (atoi(pszPort) > USHRT_MAX) + if (atoi(pszPort) < 0 || atoi(pszPort) > USHRT_MAX) port = htons(USHRT_MAX); - if (atoi(pszPort) < 0) - port = htons(0); } ip = inet_addr(psz); + return IsValid(); + } + + bool SetAddress(string strIn) + { + return SetAddress(strIn.c_str()); } IMPLEMENT_SERIALIZE @@ -274,7 +280,17 @@ public: bool IsRoutable() const { - return !(GetByte(3) == 10 || (GetByte(3) == 192 && GetByte(2) == 168) || GetByte(3) == 127 || GetByte(3) == 0); + return !(GetByte(3) == 10 || + (GetByte(3) == 192 && GetByte(2) == 168) || + GetByte(3) == 127 || + GetByte(3) == 0 || + ip == 0 || + ip == INADDR_NONE); + } + + bool IsValid() const + { + return (ip != 0 && ip != INADDR_NONE && port != htons(USHRT_MAX)); } unsigned char GetByte(int n) const diff --git a/ui.cpp b/ui.cpp index ce287e391..9185b8159 100644 --- a/ui.cpp +++ b/ui.cpp @@ -25,7 +25,6 @@ DEFINE_EVENT_TYPE(wxEVT_TABLEDELETED) CMainFrame* pframeMain = NULL; CMyTaskBarIcon* ptaskbaricon = NULL; map mapAddressBook; -map mapArgs; bool fRandSendTest = false; void RandSend(); extern int g_isPainting; @@ -283,7 +282,6 @@ CMainFrame::CMainFrame(wxWindow* parent) : CMainFrameBase(parent) fRefreshListCtrl = false; fRefreshListCtrlRunning = false; fOnSetFocusAddress = false; - pindexBestLast = NULL; m_choiceFilter->SetSelection(0); m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + " "); m_listCtrl->SetFocus(); @@ -507,6 +505,7 @@ bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex) string strStatus = FormatTxStatus(wtx); map mapValue = wtx.mapValue; wtx.nLinesDisplayed = 1; + nListViewUpdated++; // Filter if (wtx.IsCoinBase()) @@ -712,48 +711,6 @@ bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex) return true; } -void CMainFrame::RefreshStatus() -{ - static int nLastTop; - int nTop = max((int)m_listCtrl->GetTopItem(), 0); - if (nTop == nLastTop && pindexBestLast == pindexBest) - return; - - TRY_CRITICAL_BLOCK(cs_mapWallet) - { - int nStart = nTop; - int nEnd = min(nStart + 100, m_listCtrl->GetItemCount()); - if (pindexBestLast == pindexBest) - { - if (nStart >= nLastTop && nStart < nLastTop + 100) - nStart = nLastTop + 100; - if (nEnd >= nLastTop && nEnd < nLastTop + 100) - nEnd = nLastTop; - } - nLastTop = nTop; - pindexBestLast = pindexBest; - - for (int nIndex = nStart; nIndex < min(nEnd, m_listCtrl->GetItemCount()); nIndex++) - { - uint256 hash((string)GetItemText(m_listCtrl, nIndex, 1)); - map::iterator mi = mapWallet.find(hash); - if (mi == mapWallet.end()) - { - printf("CMainFrame::RefreshStatus() : tx not found in mapWallet\n"); - continue; - } - CWalletTx& wtx = (*mi).second; - if (wtx.IsCoinBase() || wtx.GetTxTime() != wtx.nTimeDisplayed) - { - if (!InsertTransaction(wtx, false, nIndex)) - m_listCtrl->DeleteItem(nIndex--); - } - else - m_listCtrl->SetItem(nIndex, 2, FormatTxStatus(wtx)); - } - } -} - void CMainFrame::RefreshListCtrl() { fRefreshListCtrl = true; @@ -832,21 +789,104 @@ void CMainFrame::OnIdle(wxIdleEvent& event) } } +void CMainFrame::RefreshStatusColumn() +{ + static int nLastTop; + static CBlockIndex* pindexLastBest; + static unsigned int nLastRefreshed; + + int nTop = max((int)m_listCtrl->GetTopItem(), 0); + if (nTop == nLastTop && pindexLastBest == pindexBest) + return; + + TRY_CRITICAL_BLOCK(cs_mapWallet) + { + int nStart = nTop; + int nEnd = min(nStart + 100, m_listCtrl->GetItemCount()); + + if (pindexLastBest == pindexBest && nLastRefreshed == nListViewUpdated) + { + // If no updates, only need to do the part that moved onto the screen + if (nStart >= nLastTop && nStart < nLastTop + 100) + nStart = nLastTop + 100; + if (nEnd >= nLastTop && nEnd < nLastTop + 100) + nEnd = nLastTop; + } + nLastTop = nTop; + pindexLastBest = pindexBest; + nLastRefreshed = nListViewUpdated; + + for (int nIndex = nStart; nIndex < min(nEnd, m_listCtrl->GetItemCount()); nIndex++) + { + uint256 hash((string)GetItemText(m_listCtrl, nIndex, 1)); + map::iterator mi = mapWallet.find(hash); + if (mi == mapWallet.end()) + { + printf("CMainFrame::RefreshStatusColumn() : tx not found in mapWallet\n"); + continue; + } + CWalletTx& wtx = (*mi).second; + if (wtx.IsCoinBase() || wtx.GetTxTime() != wtx.nTimeDisplayed) + { + if (!InsertTransaction(wtx, false, nIndex)) + m_listCtrl->DeleteItem(nIndex--); + } + else + m_listCtrl->SetItem(nIndex, 2, FormatTxStatus(wtx)); + } + } +} + void CMainFrame::OnPaint(wxPaintEvent& event) { event.Skip(); } -void DelayedRepaint(void* parg) + +unsigned int nNeedRepaint = 0; +unsigned int nLastRepaint = 0; +int64 nLastRepaintTime = 0; +int64 nRepaintInterval = 500; + +void ThreadDelayedRepaint(void* parg) { - static bool fOneThread; - if (fOneThread) - return; - fOneThread = true; - Sleep(1000); - printf("DelayedRepaint()\n"); - MainFrameRepaint(); - fOneThread = false; + while (!fShutdown) + { + if (nLastRepaint != nNeedRepaint && GetTimeMillis() - nLastRepaintTime >= nRepaintInterval) + { + nLastRepaint = nNeedRepaint; + if (pframeMain) + { + printf("DelayedRepaint\n"); + wxPaintEvent event; + pframeMain->Refresh(); + pframeMain->AddPendingEvent(event); + } + } + Sleep(nRepaintInterval); + } +} + +void MainFrameRepaint() +{ + // This is called by network code that shouldn't access pframeMain + // directly because it could still be running after the UI is closed. + if (pframeMain) + { + // Don't repaint too often + static int64 nLastRepaintRequest; + if (GetTimeMillis() - nLastRepaintRequest < 100) + { + nNeedRepaint++; + return; + } + nLastRepaintRequest = GetTimeMillis(); + + printf("MainFrameRepaint\n"); + wxPaintEvent event; + pframeMain->Refresh(); + pframeMain->AddPendingEvent(event); + } } void CMainFrame::OnPaintListCtrl(wxPaintEvent& event) @@ -854,43 +894,54 @@ void CMainFrame::OnPaintListCtrl(wxPaintEvent& event) if (ptaskbaricon) ptaskbaricon->UpdateTooltip(); - // Update listctrl contents - if (!vWalletUpdated.empty()) + // + // Slower stuff + // + static int nTransactionCount; + bool fPaintedBalance = false; + if (GetTimeMillis() - nLastRepaintTime >= nRepaintInterval) { - TRY_CRITICAL_BLOCK(cs_mapWallet) + nLastRepaint = nNeedRepaint; + nLastRepaintTime = GetTimeMillis(); + + // Update listctrl contents + if (!vWalletUpdated.empty()) { - bool fInserted = false; - foreach(uint256 hash, vWalletUpdated) + TRY_CRITICAL_BLOCK(cs_mapWallet) { - map::iterator mi = mapWallet.find(hash); - if (mi != mapWallet.end()) - fInserted |= InsertTransaction((*mi).second, false); + bool fInserted = false; + foreach(uint256 hash, vWalletUpdated) + { + map::iterator mi = mapWallet.find(hash); + if (mi != mapWallet.end()) + fInserted |= InsertTransaction((*mi).second, false); + } + vWalletUpdated.clear(); + if (fInserted) + m_listCtrl->ScrollList(0, INT_MAX); } - vWalletUpdated.clear(); - if (fInserted) - m_listCtrl->ScrollList(0, INT_MAX); } - } - - // Update status column of visible items only - RefreshStatus(); - - // Balance total - bool fRefreshed = false; - static int nTransactionCount; - TRY_CRITICAL_BLOCK(cs_mapWallet) - { - fRefreshed = true; - m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + " "); - // Count hidden and multi-line transactions - nTransactionCount = 0; - for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + // Balance total + TRY_CRITICAL_BLOCK(cs_mapWallet) { - CWalletTx& wtx = (*it).second; - nTransactionCount += wtx.nLinesDisplayed; + fPaintedBalance = true; + m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + " "); + + // Count hidden and multi-line transactions + nTransactionCount = 0; + for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + { + CWalletTx& wtx = (*it).second; + nTransactionCount += wtx.nLinesDisplayed; + } } } + if (!vWalletUpdated.empty() || !fPaintedBalance) + nNeedRepaint++; + + // Update status column of visible items only + RefreshStatusColumn(); // Update status bar string strGen = ""; @@ -903,13 +954,10 @@ void CMainFrame::OnPaintListCtrl(wxPaintEvent& event) string strStatus = strprintf(" %d connections %d blocks %d transactions", vNodes.size(), nBestHeight + 1, nTransactionCount); m_statusBar->SetStatusText(strStatus, 2); - // mapWallet was locked, try again later - if (!vWalletUpdated.empty() || !fRefreshed) - _beginthread(DelayedRepaint, 0, NULL); - m_listCtrl->OnPaint(event); } + void CrossThreadCall(wxCommandEvent& event) { if (pframeMain) @@ -994,13 +1042,6 @@ void CMainFrame::OnMenuHelpAbout(wxCommandEvent& event) void CMainFrame::OnButtonSend(wxCommandEvent& event) { - /// debug test - if (fRandSendTest) - { - RandSend(); - return; - } - // Toolbar: Send CSendDialog dialog(this); dialog.ShowModal(); @@ -1684,8 +1725,8 @@ void CSendDialog::OnButtonSend(wxCommandEvent& event) else { // Parse IP address - CAddress addr(strAddress.c_str()); - if (addr.ip == 0) + CAddress addr(strAddress); + if (!addr.IsValid()) { wxMessageBox("Invalid address ", "Send Coins"); return; @@ -1818,14 +1859,6 @@ void CSendingDialog::OnPaint(wxPaintEvent& event) wxMessageBox("Transfer cancelled ", "Sending...", wxOK, this); } event.Skip(); - - /// debug test - if (fRandSendTest && fWorkDone && fSuccess) - { - Close(); - Sleep(1000); - RandSend(); - } } @@ -3305,27 +3338,6 @@ bool CMyApp::OnInit() return false; } -map ParseParameters(int argc, char* argv[]) -{ - map mapArgs; - for (int i = 0; i < argc; i++) - { - char psz[10000]; - strcpy(psz, argv[i]); - char* pszValue = ""; - if (strchr(psz, '=')) - { - pszValue = strchr(psz, '='); - *pszValue++ = '\0'; - } - strlwr(psz); - if (psz[0] == '-') - psz[0] = '/'; - mapArgs[psz] = pszValue; - } - return mapArgs; -} - bool CMyApp::OnInit2() { #ifdef _MSC_VER @@ -3337,10 +3349,27 @@ bool CMyApp::OnInit2() // Disable malfunctioning wxWidgets debug assertion g_isPainting = 10000; #endif - - //// debug print - printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); - printf("Bitcoin version %d, Windows version %08x\n", VERSION, GetVersion()); + wxImage::AddHandler(new wxPNGHandler); + SetAppName("Bitcoin"); + + ParseParameters(argc, argv); + if (mapArgs.count("-?") || mapArgs.count("--help")) + { + string strUsage = + "Usage: bitcoin [options]\t\t\t\t\t\t\n" + "Options:\n" + " -gen\t\t Generate coins\n" + " -gen=0\t\t Don't generate coins\n" + " -min\t\t Start minimized\n" + " -datadir=\t Specify data directory\n" + " -proxy=\t Connect through socks4 proxy,\n" + " \t\t e.g. -proxy=127.0.0.1:9050 to use TOR\n" + " -addnode=\t Add a node to connect to\n" + " -connect=\t Connect only to the specified node\n" + " -?\t\t This help message\n"; + wxMessageBox(strUsage, "Bitcoin", wxOK); + exit(0); + } // // Limit to single instance per user @@ -3382,31 +3411,31 @@ bool CMyApp::OnInit2() // // Parameters // - wxImage::AddHandler(new wxPNGHandler); - mapArgs = ParseParameters(argc, argv); - - if (mapArgs.count("/datadir")) - strSetDataDir = mapArgs["/datadir"]; + if (mapArgs.count("-datadir")) + strlcpy(pszSetDataDir, mapArgs["-datadir"].c_str(), sizeof(pszSetDataDir)); - if (mapArgs.count("/debug")) + if (mapArgs.count("-debug")) fDebug = true; - if (mapArgs.count("/printtodebugger")) + if (mapArgs.count("-printtodebugger")) fPrintToDebugger = true; - if (mapArgs.count("/dropmessages")) + printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); + printf("Bitcoin version %d, Windows version %08x\n", VERSION, GetVersion()); + + if (mapArgs.count("-dropmessages")) { - nDropMessagesTest = atoi(mapArgs["/dropmessages"]); + nDropMessagesTest = atoi(mapArgs["-dropmessages"]); if (nDropMessagesTest == 0) nDropMessagesTest = 20; } - if (mapArgs.count("/loadblockindextest")) + if (mapArgs.count("-loadblockindextest")) { CTxDB txdb("r"); txdb.LoadBlockIndex(); PrintBlockTree(); - ExitProcess(0); + exit(0); } // @@ -3417,22 +3446,22 @@ bool CMyApp::OnInit2() int64 nStart; printf("Loading addresses...\n"); - nStart = PerformanceCounter(); + nStart = GetTimeMillis(); if (!LoadAddresses()) strErrors += "Error loading addr.dat \n"; - printf(" addresses %15"PRI64d"\n", PerformanceCounter() - nStart); + printf(" addresses %15"PRI64d"ms\n", GetTimeMillis() - nStart); printf("Loading block index...\n"); - nStart = PerformanceCounter(); + nStart = GetTimeMillis(); if (!LoadBlockIndex()) strErrors += "Error loading blkindex.dat \n"; - printf(" block index %15"PRI64d"\n", PerformanceCounter() - nStart); + printf(" block index %15"PRI64d"ms\n", GetTimeMillis() - nStart); printf("Loading wallet...\n"); - nStart = PerformanceCounter(); + nStart = GetTimeMillis(); if (!LoadWallet(fFirstRun)) strErrors += "Error loading wallet.dat \n"; - printf(" wallet %15"PRI64d"\n", PerformanceCounter() - nStart); + printf(" wallet %15"PRI64d"ms\n", GetTimeMillis() - nStart); printf("Done loading\n"); @@ -3457,45 +3486,59 @@ bool CMyApp::OnInit2() // // Parameters // - if (mapArgs.count("/printblockindex") || mapArgs.count("/printblocktree")) + if (mapArgs.count("-printblockindex") || mapArgs.count("-printblocktree")) { PrintBlockTree(); OnExit(); return false; } - if (mapArgs.count("/proxy")) + if (mapArgs.count("-gen")) + { + if (mapArgs["-gen"].empty()) + fGenerateBitcoins = true; + else + fGenerateBitcoins = atoi(mapArgs["-gen"].c_str()); + } + + if (mapArgs.count("-proxy")) { fUseProxy = true; - addrProxy = CAddress(mapArgs["/proxy"].c_str()); - if (addrProxy.ip == INADDR_NONE) + addrProxy = CAddress(mapArgs["-proxy"]); + if (!addrProxy.IsValid()) { - wxMessageBox("Invalid /proxy address", "Bitcoin"); + wxMessageBox("Invalid -proxy address", "Bitcoin"); OnExit(); + return false; } CWalletDB walletdb; walletdb.WriteSetting("fUseProxy", fUseProxy); walletdb.WriteSetting("addrProxy", addrProxy); } - if (mapArgs.count("/gen")) + if (mapArgs.count("-addnode")) { - if (mapArgs["/gen"].empty()) - fGenerateBitcoins = true; - else - fGenerateBitcoins = atoi(mapArgs["/gen"].c_str()); + CAddrDB addrdb; + foreach(string strAddr, mapMultiArgs["-addnode"]) + { + CAddress addr(strAddr, NODE_NETWORK); + if (addr.IsValid()) + AddAddress(addrdb, addr); + } } // // Create the main frame window // pframeMain = new CMainFrame(NULL); - if (mapArgs.count("/min")) + if (mapArgs.count("-min")) pframeMain->Iconize(true); pframeMain->Show(true); // have to show first to get taskbar button to hide pframeMain->Show(!fMinimizeToTray || !pframeMain->IsIconized()); ptaskbaricon->Show(fMinimizeToTray); + _beginthread(ThreadDelayedRepaint, 0, NULL); + if (!CheckDiskSpace()) { OnExit(); @@ -3516,7 +3559,7 @@ bool CMyApp::OnInit2() // // Tests // - if (argc >= 2 && stricmp(argv[1], "/send") == 0) + if (argc >= 2 && stricmp(argv[1], "-send") == 0) { int64 nValue = 1; if (argc >= 3) @@ -3525,7 +3568,7 @@ bool CMyApp::OnInit2() string strAddress; if (argc >= 4) strAddress = argv[3]; - CAddress addr(strAddress.c_str()); + CAddress addr(strAddress); CWalletTx wtx; wtx.mapValue["to"] = strAddress; @@ -3538,15 +3581,6 @@ bool CMyApp::OnInit2() return false; } - if (mapArgs.count("/randsendtest")) - { - if (!mapArgs["/randsendtest"].empty()) - _beginthread(ThreadRandSendTest, 0, new string(mapArgs["/randsendtest"])); - else - fRandSendTest = true; - fDebug = true; - } - return true; } @@ -3610,19 +3644,6 @@ void CMyApp::OnFatalException() -void MainFrameRepaint() -{ - // This is called by network code that shouldn't access pframeMain - // directly because it could still be running after the UI is closed. - if (pframeMain) - { - printf("MainFrameRepaint()\n"); - wxPaintEvent event; - pframeMain->Refresh(); - pframeMain->AddPendingEvent(event); - } -} - typedef WINSHELLAPI BOOL WINAPI (*PSHGETSPECIALFOLDERPATHA)(HWND hwndOwner, LPSTR lpszPath, int nFolder, BOOL fCreate); @@ -3666,7 +3687,7 @@ string StartupShortcutPath() bool GetStartOnSystemStartup() { - return FileExists(StartupShortcutPath().c_str()); + return wxFileExists(StartupShortcutPath()); } void SetStartOnSystemStartup(bool fAutoStart) @@ -3727,79 +3748,3 @@ void SetStartOnSystemStartup(bool fAutoStart) - -// randsendtest to bitcoin address -void ThreadRandSendTest(void* parg) -{ - string strAddress = *(string*)parg; - uint160 hash160; - if (!AddressToHash160(strAddress, hash160)) - { - wxMessageBox(strprintf("ThreadRandSendTest: Bitcoin address '%s' not valid ", strAddress.c_str())); - return; - } - - while (!fShutdown) - { - Sleep(GetRand(30) * 1000 + 100); - - // Message - CWalletTx wtx; - wtx.mapValue["to"] = strAddress; - wtx.mapValue["from"] = addrLocalHost.ToString(); - static int nRep; - wtx.mapValue["message"] = strprintf("randsendtest %d\n", ++nRep); - - // Value - int64 nValue = (GetRand(9) + 1) * 100 * CENT; - if (GetBalance() < nValue) - { - wxMessageBox("Out of money "); - while (GetBalance() < 1000) - Sleep(1000); - } - nValue += (nRep % 100) * CENT; - - // Send to bitcoin address - CScript scriptPubKey; - scriptPubKey << OP_DUP << OP_HASH160 << hash160 << OP_EQUALVERIFY << OP_CHECKSIG; - - if (fShutdown) - return; - if (!SendMoney(scriptPubKey, nValue, wtx)) - return; - } -} - - -// randsendtest to any connected node -void RandSend() -{ - while (vNodes.empty()) - Sleep(1000); - CAddress addr; - CRITICAL_BLOCK(cs_vNodes) - addr = vNodes[GetRand(vNodes.size())]->addr; - - // Message - CWalletTx wtx; - wtx.mapValue["to"] = addr.ToString(); - wtx.mapValue["from"] = addrLocalHost.ToString(); - static int nRep; - wtx.mapValue["message"] = strprintf("randsendtest %d\n", ++nRep); - - // Value - int64 nValue = (GetRand(999) + 1) * CENT; - if (GetBalance() < nValue) - { - wxMessageBox("Out of money "); - return; - } - - // Send to IP address - if (fShutdown) - return; - CSendingDialog* pdialog = new CSendingDialog(pframeMain, addr, nValue, wtx); - if (!pdialog->Show()) - wxMessageBox("ShowModal Failed "); -} diff --git a/ui.h b/ui.h index 9fc7e0ebe..47839e81e 100644 --- a/ui.h +++ b/ui.h @@ -83,15 +83,14 @@ public: bool fRefreshListCtrl; bool fRefreshListCtrlRunning; bool fOnSetFocusAddress; - CBlockIndex* pindexBestLast; - set setUnmaturedDisplayed; + unsigned int nListViewUpdated; void OnCrossThreadCall(wxCommandEvent& event); void InsertLine(bool fNew, int nIndex, uint256 hashKey, string strSort, const wxString& str1, const wxString& str2, const wxString& str3, const wxString& str4, const wxString& str5); bool DeleteLine(uint256 hashKey); bool InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex=-1); void RefreshListCtrl(); - void RefreshStatus(); + void RefreshStatusColumn(); }; diff --git a/util.cpp b/util.cpp index ef950920f..23b59f11f 100644 --- a/util.cpp +++ b/util.cpp @@ -5,9 +5,13 @@ #include "headers.h" +map mapArgs; +map > mapMultiArgs; bool fDebug = false; bool fPrintToDebugger = false; bool fPrintToConsole = false; +char pszSetDataDir[MAX_PATH] = ""; + @@ -68,6 +72,8 @@ void RandAddSeed() void RandAddSeedPerfmon() { +#ifdef __WXMSW__ + // Don't need this on Linux, OpenSSL automatically uses /dev/urandom // This can take up to 2 seconds, so only do it every 10 minutes static int64 nLastPerfmon; if (GetTime() < nLastPerfmon + 10 * 60) @@ -95,6 +101,7 @@ void RandAddSeedPerfmon() strftime(pszTime, sizeof(pszTime), "%x %H:%M:%S", ptmTime); printf("%s RandAddSeed() %d bytes\n", pszTime, nSize); } +#endif } @@ -304,6 +311,32 @@ vector ParseHex(const std::string& str) } +void ParseParameters(int argc, char* argv[]) +{ + mapArgs.clear(); + mapMultiArgs.clear(); + for (int i = 0; i < argc; i++) + { + char psz[10000]; + strlcpy(psz, argv[i], sizeof(psz)); + char* pszValue = ""; + if (strchr(psz, '=')) + { + pszValue = strchr(psz, '='); + *pszValue++ = '\0'; + } + strlwr(psz); + #ifdef __WXMSW__ + if (psz[0] == '/') + psz[0] = '-'; + #endif + mapArgs[psz] = pszValue; + mapMultiArgs[psz].push_back(pszValue); + } +} + + + @@ -346,15 +379,6 @@ void PrintException(std::exception* pex, const char* pszThread) -bool FileExists(const char* psz) -{ -#ifdef WIN32 - return GetFileAttributes(psz) != -1; -#else - return access(psz, 0) != -1; -#endif -} - int GetFilesize(FILE* file) { int nSavePos = ftell(file); @@ -365,6 +389,46 @@ int GetFilesize(FILE* file) return nFilesize; } +void GetDataDir(char* pszDir) +{ + // pszDir must be at least MAX_PATH length. + if (pszSetDataDir[0] != 0) + { + strlcpy(pszDir, pszSetDataDir, MAX_PATH); + static bool fMkdirDone; + if (!fMkdirDone) + { + fMkdirDone = true; + _mkdir(pszDir); + } + } + else + { + // This can be called during exceptions by printf, so we cache the + // value so we don't have to do memory allocations after that. + // wxStandardPaths::GetUserDataDir + // Return the directory for the user-dependent application data files: + // Unix: ~/.appname + // Windows: C:\Documents and Settings\username\Application Data\appname + // Mac: ~/Library/Application Support/appname + static char pszCachedDir[MAX_PATH]; + if (pszCachedDir[0] == 0) + { + strlcpy(pszCachedDir, wxStandardPaths::Get().GetUserDataDir().c_str(), sizeof(pszCachedDir)); + _mkdir(pszCachedDir); + } + strlcpy(pszDir, pszCachedDir, MAX_PATH); + } + +} + +string GetDataDir() +{ + char pszDir[MAX_PATH]; + GetDataDir(pszDir); + return pszDir; +} + diff --git a/util.h b/util.h index 5d1877600..822a049ce 100644 --- a/util.h +++ b/util.h @@ -54,16 +54,23 @@ inline T& REF(const T& val) return (T&)val; } +#ifndef __WXMSW__ +#define closesocket(s) close(s) +#define INVALID_SOCKET (SOCKET)(~0) +typedef u_int SOCKET; +#endif +extern map mapArgs; +extern map > mapMultiArgs; extern bool fDebug; extern bool fPrintToDebugger; extern bool fPrintToConsole; -extern map mapArgs; +extern char pszSetDataDir[MAX_PATH]; void RandAddSeed(); void RandAddSeedPerfmon(); @@ -77,8 +84,10 @@ string FormatMoney(int64 n, bool fPlus=false); bool ParseMoney(const char* pszIn, int64& nRet); vector ParseHex(const char* psz); vector ParseHex(const std::string& str); -bool FileExists(const char* psz); +void ParseParameters(int argc, char* argv[]); int GetFilesize(FILE* file); +void GetDataDir(char* pszDirRet); +string GetDataDir(); uint64 GetRand(uint64 nMax); int64 GetTime(); int64 GetAdjustedTime(); @@ -172,9 +181,14 @@ inline int OutputDebugStringF(const char* pszFormat, ...) if (!fPrintToConsole) { // print to debug.log - FILE* fileout = fopen("debug.log", "a"); + char pszFile[MAX_PATH+100]; + GetDataDir(pszFile); + strlcat(pszFile, "\\debug.log", sizeof(pszFile)); + FILE* fileout = fopen(pszFile, "a"); if (fileout) { + //// Debug print useful for profiling + //fprintf(fileout, " %"PRI64d" ", wxGetLocalTimeMillis().GetValue()); va_list arg_ptr; va_start(arg_ptr, pszFormat); ret = vfprintf(fileout, pszFormat, arg_ptr); @@ -321,22 +335,25 @@ inline void PrintHex(vector vch, const char* pszFormat="%s", bool { printf(pszFormat, HexStr(vch, fSpaces).c_str()); } - inline int64 PerformanceCounter() { - int64 nCounter = 0; + int64 nCounter = 0; #ifdef __WXMSW__ - QueryPerformanceCounter((LARGE_INTEGER*)&nCounter); + QueryPerformanceCounter((LARGE_INTEGER*)&nCounter); #else - // this could be changed to reading /dev/urandom - timeval t; - gettimeofday(&t, NULL); - nCounter += t.tv_sec * 1000000 + t.tv_usec; + timeval t; + gettimeofday(&t, NULL); + nCounter = t.tv_sec * 1000000 + t.tv_usec; #endif return nCounter; } +inline int64 GetTimeMillis() +{ + return wxGetLocalTimeMillis().GetValue(); +} + #ifndef __WXMSW__ inline void Sleep(unsigned int nMilliseconds) { @@ -354,8 +371,10 @@ inline void Sleep(unsigned int nMilliseconds) inline void heapchk() { +#ifdef __WXMSW__ if (_heapchk() != _HEAPOK) DebugBreak(); +#endif } // Randomize the stack to help protect against buffer overrun exploits