move debug.log and db.log to data dir, portable GetDataDir, optimize GetBalance, fix repaint bogdown, -addnode and -? switches

This commit is contained in:
s_nakamoto 2009-11-01 01:16:51 +00:00
parent 99142385da
commit e66ec79b18
12 changed files with 415 additions and 381 deletions

View file

@ -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

19
db.cpp
View file

@ -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++);
}
}

View file

@ -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");

5
irc.h
View file

@ -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);

View file

@ -42,7 +42,6 @@ map<uint160, vector<unsigned char> > 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;
}

20
main.h
View file

@ -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

34
net.cpp
View file

@ -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<int, 10> 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)

78
net.h
View file

@ -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

455
ui.cpp
View file

@ -25,7 +25,6 @@ DEFINE_EVENT_TYPE(wxEVT_TABLEDELETED)
CMainFrame* pframeMain = NULL;
CMyTaskBarIcon* ptaskbaricon = NULL;
map<string, string> mapAddressBook;
map<string, string> 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<string, string> 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<uint256, CWalletTx>::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<uint256, CWalletTx>::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)
{
nLastRepaint = nNeedRepaint;
nLastRepaintTime = GetTimeMillis();
// Update listctrl contents
if (!vWalletUpdated.empty())
{
TRY_CRITICAL_BLOCK(cs_mapWallet)
{
bool fInserted = false;
foreach(uint256 hash, vWalletUpdated)
{
map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
if (mi != mapWallet.end())
fInserted |= InsertTransaction((*mi).second, false);
}
vWalletUpdated.clear();
if (fInserted)
m_listCtrl->ScrollList(0, INT_MAX);
}
}
// Balance total
TRY_CRITICAL_BLOCK(cs_mapWallet)
{
bool fInserted = false;
foreach(uint256 hash, vWalletUpdated)
fPaintedBalance = true;
m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + " ");
// Count hidden and multi-line transactions
nTransactionCount = 0;
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
if (mi != mapWallet.end())
fInserted |= InsertTransaction((*mi).second, false);
CWalletTx& wtx = (*it).second;
nTransactionCount += wtx.nLinesDisplayed;
}
vWalletUpdated.clear();
if (fInserted)
m_listCtrl->ScrollList(0, INT_MAX);
}
}
if (!vWalletUpdated.empty() || !fPaintedBalance)
nNeedRepaint++;
// 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<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
CWalletTx& wtx = (*it).second;
nTransactionCount += wtx.nLinesDisplayed;
}
}
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<string, string> ParseParameters(int argc, char* argv[])
{
map<string, string> 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
wxImage::AddHandler(new wxPNGHandler);
SetAppName("Bitcoin");
//// 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());
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=<dir>\t Specify data directory\n"
" -proxy=<ip:port>\t Connect through socks4 proxy,\n"
" \t\t e.g. -proxy=127.0.0.1:9050 to use TOR\n"
" -addnode=<ip>\t Add a node to connect to\n"
" -connect=<ip>\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"))
strlcpy(pszSetDataDir, mapArgs["-datadir"].c_str(), sizeof(pszSetDataDir));
if (mapArgs.count("/datadir"))
strSetDataDir = mapArgs["/datadir"];
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 ");
}

5
ui.h
View file

@ -83,15 +83,14 @@ public:
bool fRefreshListCtrl;
bool fRefreshListCtrlRunning;
bool fOnSetFocusAddress;
CBlockIndex* pindexBestLast;
set<uint256> 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();
};

View file

@ -5,9 +5,13 @@
#include "headers.h"
map<string, string> mapArgs;
map<string, vector<string> > 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<unsigned char> 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;
}

39
util.h
View file

@ -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<string, string> mapArgs;
extern map<string, vector<string> > mapMultiArgs;
extern bool fDebug;
extern bool fPrintToDebugger;
extern bool fPrintToConsole;
extern map<string, string> 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<unsigned char> ParseHex(const char* psz);
vector<unsigned char> 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<unsigned char> 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