bugfix Db::open/close and zombie sockets bugs fix double-close of socket handle,

keep databases open,
close db cursors,
initial block download in batches of 500 blocks,
fix misc warnings,
subver linux-test8
This commit is contained in:
s_nakamoto 2009-11-18 19:19:41 +00:00
parent 01fe1d2137
commit e4db374421
23 changed files with 307 additions and 187 deletions

View File

@ -13,18 +13,18 @@ UNIX BUILD NOTES
Dependencies Dependencies
------------ ------------
Install the dev files for the shared libraries:
apt-get install build-essential apt-get install build-essential
apt-get install libgtk2.0-dev apt-get install libgtk2.0-dev
apt-get install libssl-dev apt-get install libssl-dev
apt-get install libdb4.7-dev
apt-get install libdb4.7++-dev
apt-get install libboost-dev
Libraries you need to obtain separately and build: Libraries you need to obtain separately and build:
default path download default path download
wxWidgets \wxwidgets http://www.wxwidgets.org/downloads/ wxWidgets \wxwidgets http://www.wxwidgets.org/downloads/
Berkeley DB \db http://www.oracle.com/technology/software/products/berkeley-db/index.html
Boost \boost http://www.boost.org/users/download/
Their licenses: Licenses:
wxWidgets LGPL 2.1 with very liberal exceptions wxWidgets LGPL 2.1 with very liberal exceptions
Berkeley DB New BSD license with additional requirement that linked software must be free open source Berkeley DB New BSD license with additional requirement that linked software must be free open source
Boost MIT-like license Boost MIT-like license
@ -59,15 +59,9 @@ make install
ldconfig ldconfig
Berkeley DB
-----------
cd /usr/local/db-4.7.25.NC/build_unix
../dist/configure --enable-cxx
make
Boost Boost
----- -----
If you download and build Boost yourself
cd /usr/local/boost_1_40_0 cd /usr/local/boost_1_40_0
su su
./bootstrap.sh ./bootstrap.sh

136
db.cpp
View File

@ -20,6 +20,7 @@ static CCriticalSection cs_db;
static bool fDbEnvInit = false; static bool fDbEnvInit = false;
DbEnv dbenv(0); DbEnv dbenv(0);
static map<string, int> mapFileUseCount; static map<string, int> mapFileUseCount;
static map<string, Db*> mapDb;
class CDBInit class CDBInit
{ {
@ -39,21 +40,17 @@ public:
instance_of_cdbinit; instance_of_cdbinit;
CDB::CDB(const char* pszFile, const char* pszMode, bool fTxn) : pdb(NULL) CDB::CDB(const char* pszFile, const char* pszMode) : pdb(NULL)
{ {
int ret; int ret;
if (pszFile == NULL) if (pszFile == NULL)
return; return;
fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w'));
bool fCreate = strchr(pszMode, 'c'); bool fCreate = strchr(pszMode, 'c');
bool fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w'));
unsigned int nFlags = DB_THREAD; unsigned int nFlags = DB_THREAD;
if (fCreate) if (fCreate)
nFlags |= DB_CREATE; nFlags |= DB_CREATE;
else if (fReadOnly)
nFlags |= DB_RDONLY;
if (!fReadOnly || fTxn)
nFlags |= DB_AUTO_COMMIT;
CRITICAL_BLOCK(cs_db) CRITICAL_BLOCK(cs_db)
{ {
@ -72,7 +69,7 @@ CDB::CDB(const char* pszFile, const char* pszMode, bool fTxn) : pdb(NULL)
dbenv.set_lk_max_locks(10000); dbenv.set_lk_max_locks(10000);
dbenv.set_lk_max_objects(10000); dbenv.set_lk_max_objects(10000);
dbenv.set_errfile(fopen(strErrorFile.c_str(), "a")); /// debug dbenv.set_errfile(fopen(strErrorFile.c_str(), "a")); /// debug
///dbenv.log_set_config(DB_LOG_AUTO_REMOVE, 1); /// causes corruption dbenv.set_flags(DB_AUTO_COMMIT, 1);
ret = dbenv.open(strDataDir.c_str(), ret = dbenv.open(strDataDir.c_str(),
DB_CREATE | DB_CREATE |
DB_INIT_LOCK | DB_INIT_LOCK |
@ -90,31 +87,39 @@ CDB::CDB(const char* pszFile, const char* pszMode, bool fTxn) : pdb(NULL)
strFile = pszFile; strFile = pszFile;
++mapFileUseCount[strFile]; ++mapFileUseCount[strFile];
pdb = mapDb[strFile];
if (pdb == NULL)
{
pdb = new Db(&dbenv, 0);
ret = pdb->open(NULL, // Txn pointer
pszFile, // Filename
"main", // Logical db name
DB_BTREE, // Database type
nFlags, // Flags
0);
if (ret > 0)
{
delete pdb;
pdb = NULL;
CRITICAL_BLOCK(cs_db)
--mapFileUseCount[strFile];
strFile = "";
throw runtime_error(strprintf("CDB() : can't open database file %s, error %d\n", pszFile, ret));
}
if (fCreate && !Exists(string("version")))
{
bool fTmp = fReadOnly;
fReadOnly = false;
WriteVersion(VERSION);
fReadOnly = fTmp;
}
mapDb[strFile] = pdb;
}
} }
pdb = new Db(&dbenv, 0);
ret = pdb->open(NULL, // Txn pointer
pszFile, // Filename
"main", // Logical db name
DB_BTREE, // Database type
nFlags, // Flags
0);
if (ret > 0)
{
delete pdb;
pdb = NULL;
CRITICAL_BLOCK(cs_db)
--mapFileUseCount[strFile];
strFile = "";
throw runtime_error(strprintf("CDB() : can't open database file %s, error %d\n", pszFile, ret));
}
if (fCreate && !Exists(string("version")))
WriteVersion(VERSION);
RandAddSeed();
} }
void CDB::Close() void CDB::Close()
@ -124,8 +129,6 @@ void CDB::Close()
if (!vTxn.empty()) if (!vTxn.empty())
vTxn.front()->abort(); vTxn.front()->abort();
vTxn.clear(); vTxn.clear();
pdb->close(0);
delete pdb;
pdb = NULL; pdb = NULL;
dbenv.txn_checkpoint(0, 0, 0); dbenv.txn_checkpoint(0, 0, 0);
@ -135,6 +138,21 @@ void CDB::Close()
RandAddSeed(); RandAddSeed();
} }
void CloseDb(const string& strFile)
{
CRITICAL_BLOCK(cs_db)
{
if (mapDb[strFile] != NULL)
{
// Close the database handle
Db* pdb = mapDb[strFile];
pdb->close(0);
delete pdb;
mapDb[strFile] = NULL;
}
}
}
void DBFlush(bool fShutdown) void DBFlush(bool fShutdown)
{ {
// Flush log data to the actual data file // Flush log data to the actual data file
@ -144,14 +162,18 @@ void DBFlush(bool fShutdown)
return; return;
CRITICAL_BLOCK(cs_db) CRITICAL_BLOCK(cs_db)
{ {
dbenv.txn_checkpoint(0, 0, 0);
map<string, int>::iterator mi = mapFileUseCount.begin(); map<string, int>::iterator mi = mapFileUseCount.begin();
while (mi != mapFileUseCount.end()) while (mi != mapFileUseCount.end())
{ {
string strFile = (*mi).first; string strFile = (*mi).first;
int nRefCount = (*mi).second; int nRefCount = (*mi).second;
printf("%s refcount=%d\n", strFile.c_str(), nRefCount);
if (nRefCount == 0) if (nRefCount == 0)
{ {
// Move log data to the dat file
CloseDb(strFile);
dbenv.txn_checkpoint(0, 0, 0);
printf("%s flush\n", strFile.c_str());
dbenv.lsn_reset(strFile.c_str(), 0); dbenv.lsn_reset(strFile.c_str(), 0);
mapFileUseCount.erase(mi++); mapFileUseCount.erase(mi++);
} }
@ -238,7 +260,10 @@ bool CTxDB::ReadOwnerTxes(uint160 hash160, int nMinHeight, vector<CTransaction>&
if (ret == DB_NOTFOUND) if (ret == DB_NOTFOUND)
break; break;
else if (ret != 0) else if (ret != 0)
{
pcursor->close();
return false; return false;
}
// Unserialize // Unserialize
string strType; string strType;
@ -255,9 +280,14 @@ bool CTxDB::ReadOwnerTxes(uint160 hash160, int nMinHeight, vector<CTransaction>&
{ {
vtx.resize(vtx.size()+1); vtx.resize(vtx.size()+1);
if (!vtx.back().ReadFromDisk(pos)) if (!vtx.back().ReadFromDisk(pos))
{
pcursor->close();
return false; return false;
}
} }
} }
pcursor->close();
return true; return true;
} }
@ -379,6 +409,7 @@ bool CTxDB::LoadBlockIndex()
break; break;
} }
} }
pcursor->close();
if (!ReadHashBestChain(hashBestChain)) if (!ReadHashBestChain(hashBestChain))
{ {
@ -391,7 +422,7 @@ bool CTxDB::LoadBlockIndex()
return error("CTxDB::LoadBlockIndex() : blockindex for hashBestChain not found"); return error("CTxDB::LoadBlockIndex() : blockindex for hashBestChain not found");
pindexBest = mapBlockIndex[hashBestChain]; pindexBest = mapBlockIndex[hashBestChain];
nBestHeight = pindexBest->nHeight; nBestHeight = pindexBest->nHeight;
printf("LoadBlockIndex(): hashBestChain=%s height=%d\n", hashBestChain.ToString().substr(0,14).c_str(), nBestHeight); printf("LoadBlockIndex(): hashBestChain=%s height=%d\n", hashBestChain.ToString().substr(0,16).c_str(), nBestHeight);
return true; return true;
} }
@ -456,6 +487,7 @@ bool CAddrDB::LoadAddresses()
mapAddresses.insert(make_pair(addr.GetKey(), addr)); mapAddresses.insert(make_pair(addr.GetKey(), addr));
} }
} }
pcursor->close();
printf("Loaded %d addresses\n", mapAddresses.size()); printf("Loaded %d addresses\n", mapAddresses.size());
@ -558,7 +590,7 @@ bool CWalletDB::LoadWallet(vector<unsigned char>& vchDefaultKeyRet)
//printf(" %12I64d %s %s %s\n", //printf(" %12I64d %s %s %s\n",
// wtx.vout[0].nValue, // wtx.vout[0].nValue,
// DateTimeStrFormat("%x %H:%M:%S", wtx.nTime).c_str(), // DateTimeStrFormat("%x %H:%M:%S", wtx.nTime).c_str(),
// wtx.hashBlock.ToString().substr(0,14).c_str(), // wtx.hashBlock.ToString().substr(0,16).c_str(),
// wtx.mapValue["message"].c_str()); // wtx.mapValue["message"].c_str());
} }
else if (strType == "key") else if (strType == "key")
@ -596,6 +628,7 @@ bool CWalletDB::LoadWallet(vector<unsigned char>& vchDefaultKeyRet)
} }
} }
pcursor->close();
} }
printf("fShowGenerated = %d\n", fShowGenerated); printf("fShowGenerated = %d\n", fShowGenerated);
@ -655,6 +688,8 @@ void ThreadFlushWalletDB(void* parg)
if (fOneThread) if (fOneThread)
return; return;
fOneThread = true; fOneThread = true;
if (mapArgs.count("-noflushwallet"))
return;
unsigned int nLastSeen = nWalletDBUpdated; unsigned int nLastSeen = nWalletDBUpdated;
unsigned int nLastFlushed = nWalletDBUpdated; unsigned int nLastFlushed = nWalletDBUpdated;
@ -669,24 +704,37 @@ void ThreadFlushWalletDB(void* parg)
nLastWalletUpdate = GetTime(); nLastWalletUpdate = GetTime();
} }
if (nLastFlushed != nWalletDBUpdated && nLastWalletUpdate < GetTime() - 1) if (nLastFlushed != nWalletDBUpdated && GetTime() - nLastWalletUpdate >= 2)
{ {
TRY_CRITICAL_BLOCK(cs_db) TRY_CRITICAL_BLOCK(cs_db)
{ {
string strFile = "wallet.dat"; // Don't do this if any databases are in use
map<string, int>::iterator mi = mapFileUseCount.find(strFile); int nRefCount = 0;
if (mi != mapFileUseCount.end()) map<string, int>::iterator mi = mapFileUseCount.begin();
while (mi != mapFileUseCount.end())
{ {
int nRefCount = (*mi).second; nRefCount += (*mi).second;
if (nRefCount == 0 && !fShutdown) mi++;
}
if (nRefCount == 0 && !fShutdown)
{
string strFile = "wallet.dat";
map<string, int>::iterator mi = mapFileUseCount.find(strFile);
if (mi != mapFileUseCount.end())
{ {
// Flush wallet.dat so it's self contained printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
printf("Flushing wallet.dat\n");
nLastFlushed = nWalletDBUpdated; nLastFlushed = nWalletDBUpdated;
int64 nStart = GetTimeMillis(); int64 nStart = GetTimeMillis();
// Flush wallet.dat so it's self contained
CloseDb(strFile);
dbenv.txn_checkpoint(0, 0, 0); dbenv.txn_checkpoint(0, 0, 0);
dbenv.lsn_reset(strFile.c_str(), 0); dbenv.lsn_reset(strFile.c_str(), 0);
printf("Flushed wallet.dat %"PRI64d"ms\n", GetTimeMillis() - nStart);
mapFileUseCount.erase(mi++); mapFileUseCount.erase(mi++);
printf("Flushed wallet.dat %"PRI64d"ms\n", GetTimeMillis() - nStart);
} }
} }
} }

17
db.h
View File

@ -32,8 +32,9 @@ protected:
Db* pdb; Db* pdb;
string strFile; string strFile;
vector<DbTxn*> vTxn; vector<DbTxn*> vTxn;
bool fReadOnly;
explicit CDB(const char* pszFile, const char* pszMode="r+", bool fTxn=false); explicit CDB(const char* pszFile, const char* pszMode="r+");
~CDB() { Close(); } ~CDB() { Close(); }
public: public:
void Close(); void Close();
@ -77,6 +78,8 @@ protected:
{ {
if (!pdb) if (!pdb)
return false; return false;
if (fReadOnly)
assert(("Write called on database in read-only mode", false));
// Key // Key
CDataStream ssKey(SER_DISK); CDataStream ssKey(SER_DISK);
@ -104,6 +107,8 @@ protected:
{ {
if (!pdb) if (!pdb)
return false; return false;
if (fReadOnly)
assert(("Erase called on database in read-only mode", false));
// Key // Key
CDataStream ssKey(SER_DISK); CDataStream ssKey(SER_DISK);
@ -254,7 +259,7 @@ public:
class CTxDB : public CDB class CTxDB : public CDB
{ {
public: public:
CTxDB(const char* pszMode="r+", bool fTxn=false) : CDB(!fClient ? "blkindex.dat" : NULL, pszMode, fTxn) { } CTxDB(const char* pszMode="r+") : CDB(!fClient ? "blkindex.dat" : NULL, pszMode) { }
private: private:
CTxDB(const CTxDB&); CTxDB(const CTxDB&);
void operator=(const CTxDB&); void operator=(const CTxDB&);
@ -283,7 +288,7 @@ public:
class CReviewDB : public CDB class CReviewDB : public CDB
{ {
public: public:
CReviewDB(const char* pszMode="r+", bool fTxn=false) : CDB("reviews.dat", pszMode, fTxn) { } CReviewDB(const char* pszMode="r+") : CDB("reviews.dat", pszMode) { }
private: private:
CReviewDB(const CReviewDB&); CReviewDB(const CReviewDB&);
void operator=(const CReviewDB&); void operator=(const CReviewDB&);
@ -309,7 +314,7 @@ public:
class CMarketDB : public CDB class CMarketDB : public CDB
{ {
public: public:
CMarketDB(const char* pszMode="r+", bool fTxn=false) : CDB("market.dat", pszMode, fTxn) { } CMarketDB(const char* pszMode="r+") : CDB("market.dat", pszMode) { }
private: private:
CMarketDB(const CMarketDB&); CMarketDB(const CMarketDB&);
void operator=(const CMarketDB&); void operator=(const CMarketDB&);
@ -322,7 +327,7 @@ private:
class CAddrDB : public CDB class CAddrDB : public CDB
{ {
public: public:
CAddrDB(const char* pszMode="r+", bool fTxn=false) : CDB("addr.dat", pszMode, fTxn) { } CAddrDB(const char* pszMode="r+") : CDB("addr.dat", pszMode) { }
private: private:
CAddrDB(const CAddrDB&); CAddrDB(const CAddrDB&);
void operator=(const CAddrDB&); void operator=(const CAddrDB&);
@ -341,7 +346,7 @@ bool LoadAddresses();
class CWalletDB : public CDB class CWalletDB : public CDB
{ {
public: public:
CWalletDB(const char* pszMode="r+", bool fTxn=false) : CDB("wallet.dat", pszMode, fTxn) { } CWalletDB(const char* pszMode="r+") : CDB("wallet.dat", pszMode) { }
private: private:
CWalletDB(const CWalletDB&); CWalletDB(const CWalletDB&);
void operator=(const CWalletDB&); void operator=(const CWalletDB&);

14
irc.cpp
View File

@ -159,15 +159,12 @@ void ThreadIRCSeed(void* parg)
SetThreadPriority(THREAD_PRIORITY_NORMAL); SetThreadPriority(THREAD_PRIORITY_NORMAL);
int nErrorWait = 10; int nErrorWait = 10;
int nRetryWait = 10; int nRetryWait = 10;
bool fTOR = (fUseProxy && addrProxy.port == htons(9050));
// IRC server blocks TOR users
if (fUseProxy && addrProxy.port == htons(9050))
return;
while (!fShutdown) while (!fShutdown)
{ {
CAddress addrConnect("216.155.130.130:6667"); CAddress addrConnect("216.155.130.130:6667");
if (!(fUseProxy && addrProxy.port == htons(9050))) if (!fTOR)
{ {
struct hostent* phostent = gethostbyname("chat.freenode.net"); struct hostent* phostent = gethostbyname("chat.freenode.net");
if (phostent && phostent->h_addr_list && phostent->h_addr_list[0]) if (phostent && phostent->h_addr_list && phostent->h_addr_list[0])
@ -188,6 +185,7 @@ void ThreadIRCSeed(void* parg)
if (!RecvUntil(hSocket, "Found your hostname", "using your IP address instead", "Couldn't look up your hostname")) if (!RecvUntil(hSocket, "Found your hostname", "using your IP address instead", "Couldn't look up your hostname"))
{ {
closesocket(hSocket); closesocket(hSocket);
hSocket = INVALID_SOCKET;
nErrorWait = nErrorWait * 11 / 10; nErrorWait = nErrorWait * 11 / 10;
if (Wait(nErrorWait += 60)) if (Wait(nErrorWait += 60))
continue; continue;
@ -208,6 +206,7 @@ void ThreadIRCSeed(void* parg)
if (!RecvUntil(hSocket, " 004 ")) if (!RecvUntil(hSocket, " 004 "))
{ {
closesocket(hSocket); closesocket(hSocket);
hSocket = INVALID_SOCKET;
nErrorWait = nErrorWait * 11 / 10; nErrorWait = nErrorWait * 11 / 10;
if (Wait(nErrorWait += 60)) if (Wait(nErrorWait += 60))
continue; continue;
@ -269,6 +268,11 @@ void ThreadIRCSeed(void* parg)
} }
} }
closesocket(hSocket); closesocket(hSocket);
hSocket = INVALID_SOCKET;
// IRC usually blocks TOR, so only try once
if (fTOR)
return;
if (GetTime() - nStart > 20 * 60) if (GetTime() - nStart > 20 * 60)
{ {

View File

@ -760,7 +760,7 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast)
bnNew = bnProofOfWorkLimit; bnNew = bnProofOfWorkLimit;
/// debug print /// debug print
printf("\n\n\nGetNextWorkRequired RETARGET *****\n"); printf("GetNextWorkRequired RETARGET\n");
printf("nTargetTimespan = %d nActualTimespan = %d\n", nTargetTimespan, nActualTimespan); printf("nTargetTimespan = %d nActualTimespan = %d\n", nTargetTimespan, nActualTimespan);
printf("Before: %08x %s\n", pindexLast->nBits, CBigNum().SetCompact(pindexLast->nBits).getuint256().ToString().c_str()); printf("Before: %08x %s\n", pindexLast->nBits, CBigNum().SetCompact(pindexLast->nBits).getuint256().ToString().c_str());
printf("After: %08x %s\n", bnNew.GetCompact(), bnNew.getuint256().ToString().c_str()); printf("After: %08x %s\n", bnNew.GetCompact(), bnNew.getuint256().ToString().c_str());
@ -1013,7 +1013,7 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex)
bool Reorganize(CTxDB& txdb, CBlockIndex* pindexNew) bool Reorganize(CTxDB& txdb, CBlockIndex* pindexNew)
{ {
printf("*** REORGANIZE ***\n"); printf("REORGANIZE\n");
// Find the fork // Find the fork
CBlockIndex* pfork = pindexBest; CBlockIndex* pfork = pindexBest;
@ -1114,7 +1114,7 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos)
// Check for duplicate // Check for duplicate
uint256 hash = GetHash(); uint256 hash = GetHash();
if (mapBlockIndex.count(hash)) if (mapBlockIndex.count(hash))
return error("AddToBlockIndex() : %s already exists", hash.ToString().substr(0,14).c_str()); return error("AddToBlockIndex() : %s already exists", hash.ToString().substr(0,16).c_str());
// Construct new block index object // Construct new block index object
CBlockIndex* pindexNew = new CBlockIndex(nFile, nBlockPos, *this); CBlockIndex* pindexNew = new CBlockIndex(nFile, nBlockPos, *this);
@ -1174,7 +1174,7 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos)
pindexBest = pindexNew; pindexBest = pindexNew;
nBestHeight = pindexBest->nHeight; nBestHeight = pindexBest->nHeight;
nTransactionsUpdated++; nTransactionsUpdated++;
printf("AddToBlockIndex: new best=%s height=%d\n", hashBestChain.ToString().substr(0,14).c_str(), nBestHeight); printf("AddToBlockIndex: new best=%s height=%d\n", hashBestChain.ToString().substr(0,16).c_str(), nBestHeight);
} }
txdb.TxnCommit(); txdb.TxnCommit();
@ -1294,9 +1294,9 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock)
// Check for duplicate // Check for duplicate
uint256 hash = pblock->GetHash(); uint256 hash = pblock->GetHash();
if (mapBlockIndex.count(hash)) if (mapBlockIndex.count(hash))
return error("ProcessBlock() : already have block %d %s", mapBlockIndex[hash]->nHeight, hash.ToString().substr(0,14).c_str()); return error("ProcessBlock() : already have block %d %s", mapBlockIndex[hash]->nHeight, hash.ToString().substr(0,16).c_str());
if (mapOrphanBlocks.count(hash)) if (mapOrphanBlocks.count(hash))
return error("ProcessBlock() : already have block (orphan) %s", hash.ToString().substr(0,14).c_str()); return error("ProcessBlock() : already have block (orphan) %s", hash.ToString().substr(0,16).c_str());
// Preliminary checks // Preliminary checks
if (!pblock->CheckBlock()) if (!pblock->CheckBlock())
@ -1308,7 +1308,7 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock)
// If don't already have its previous block, shunt it off to holding area until we get it // If don't already have its previous block, shunt it off to holding area until we get it
if (!mapBlockIndex.count(pblock->hashPrevBlock)) if (!mapBlockIndex.count(pblock->hashPrevBlock))
{ {
printf("ProcessBlock: ORPHAN BLOCK, prev=%s\n", pblock->hashPrevBlock.ToString().substr(0,14).c_str()); printf("ProcessBlock: ORPHAN BLOCK, prev=%s\n", pblock->hashPrevBlock.ToString().substr(0,16).c_str());
mapOrphanBlocks.insert(make_pair(hash, pblock)); mapOrphanBlocks.insert(make_pair(hash, pblock));
mapOrphanBlocksByPrev.insert(make_pair(pblock->hashPrevBlock, pblock)); mapOrphanBlocksByPrev.insert(make_pair(pblock->hashPrevBlock, pblock));
@ -1503,11 +1503,11 @@ bool LoadBlockIndex(bool fAllowNew)
// vMerkleTree: 4a5e1e // vMerkleTree: 4a5e1e
// Genesis block // Genesis block
char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks"; const char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks";
CTransaction txNew; CTransaction txNew;
txNew.vin.resize(1); txNew.vin.resize(1);
txNew.vout.resize(1); txNew.vout.resize(1);
txNew.vin[0].scriptSig = CScript() << 486604799 << CBigNum(4) << vector<unsigned char>((unsigned char*)pszTimestamp, (unsigned char*)pszTimestamp + strlen(pszTimestamp)); txNew.vin[0].scriptSig = CScript() << 486604799 << CBigNum(4) << vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
txNew.vout[0].nValue = 50 * COIN; txNew.vout[0].nValue = 50 * COIN;
txNew.vout[0].scriptPubKey = CScript() << CBigNum("0x5F1DF16B2B704C8A578D0BBAF74D385CDE12C11EE50455F3C438EF4C3FBCF649B6DE611FEAE06279A60939E028A8D65C10B73071A6F16719274855FEB0FD8A6704") << OP_CHECKSIG; txNew.vout[0].scriptPubKey = CScript() << CBigNum("0x5F1DF16B2B704C8A578D0BBAF74D385CDE12C11EE50455F3C438EF4C3FBCF649B6DE611FEAE06279A60939E028A8D65C10B73071A6F16719274855FEB0FD8A6704") << OP_CHECKSIG;
CBlock block; CBlock block;
@ -1519,7 +1519,7 @@ bool LoadBlockIndex(bool fAllowNew)
block.nBits = 0x1d00ffff; block.nBits = 0x1d00ffff;
block.nNonce = 2083236893; block.nNonce = 2083236893;
//// debug print, delete this later //// debug print
printf("%s\n", block.GetHash().ToString().c_str()); printf("%s\n", block.GetHash().ToString().c_str());
printf("%s\n", block.hashMerkleRoot.ToString().c_str()); printf("%s\n", block.hashMerkleRoot.ToString().c_str());
printf("%s\n", hashGenesisBlock.ToString().c_str()); printf("%s\n", hashGenesisBlock.ToString().c_str());
@ -1592,7 +1592,7 @@ void PrintBlockTree()
pindex->nHeight, pindex->nHeight,
pindex->nFile, pindex->nFile,
pindex->nBlockPos, pindex->nBlockPos,
block.GetHash().ToString().substr(0,14).c_str(), block.GetHash().ToString().substr(0,16).c_str(),
DateTimeStrFormat("%x %H:%M:%S", block.nTime).c_str(), DateTimeStrFormat("%x %H:%M:%S", block.nTime).c_str(),
block.vtx.size()); block.vtx.size());
@ -1912,6 +1912,18 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
CBlock block; CBlock block;
block.ReadFromDisk((*mi).second, !pfrom->fClient); block.ReadFromDisk((*mi).second, !pfrom->fClient);
pfrom->PushMessage("block", block); pfrom->PushMessage("block", block);
// Trigger them to send a getblocks request for the next batch of inventory
if (inv.hash == pfrom->hashContinue)
{
// Bypass PushInventory, this must send even if redundant,
// and we want it right after the last block so they don't
// wait for other stuff first.
vector<CInv> vInv;
vInv.push_back(CInv(MSG_BLOCK, hashBestChain));
pfrom->PushMessage("inv", vInv);
pfrom->hashContinue = 0;
}
} }
} }
else if (inv.IsKnownType()) else if (inv.IsKnownType())
@ -1948,25 +1960,23 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
// Send the rest of the chain // Send the rest of the chain
if (pindex) if (pindex)
pindex = pindex->pnext; pindex = pindex->pnext;
printf("getblocks %d to %s\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().substr(0,14).c_str()); printf("getblocks %d to %s\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().substr(0,16).c_str());
int nLimit = 500;
for (; pindex; pindex = pindex->pnext) for (; pindex; pindex = pindex->pnext)
{ {
if (pindex->GetBlockHash() == hashStop) if (pindex->GetBlockHash() == hashStop)
{ {
printf(" getblocks stopping at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString().substr(0,14).c_str()); printf(" getblocks stopping at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString().substr(0,16).c_str());
break; break;
} }
pfrom->PushInventory(CInv(MSG_BLOCK, pindex->GetBlockHash()));
// Bypass setInventoryKnown in case an inventory message got lost if (--nLimit <= 0)
CRITICAL_BLOCK(pfrom->cs_inventory)
{ {
CInv inv(MSG_BLOCK, pindex->GetBlockHash()); // When this block is requested, we'll send an inv that'll make them
// returns true if wasn't already contained in the set // getblocks the next batch of inventory.
if (pfrom->setInventoryKnown2.insert(inv).second) printf(" getblocks stopping at limit %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString().substr(0,16).c_str());
{ pfrom->hashContinue = pindex->GetBlockHash();
pfrom->setInventoryKnown.erase(inv); break;
pfrom->vInventoryToSend.push_back(inv);
}
} }
} }
} }
@ -2049,7 +2059,13 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
vRecv >> *pblock; vRecv >> *pblock;
//// debug print //// debug print
printf("received block:\n"); pblock->print(); if (false)
{
printf("received block:\n");
pblock->print();
}
else
printf("received block %s\n", pblock->GetHash().ToString().substr(0,16).c_str());
CInv inv(MSG_BLOCK, pblock->GetHash()); CInv inv(MSG_BLOCK, pblock->GetHash());
pfrom->AddInventoryKnown(inv); pfrom->AddInventoryKnown(inv);
@ -2175,9 +2191,13 @@ bool SendMessages(CNode* pto)
if (pto->nVersion == 0) if (pto->nVersion == 0)
return true; return true;
// Keep-alive ping
if (pto->nLastSend && GetTime() - pto->nLastSend > 12 * 60 && pto->vSend.empty())
pto->PushMessage("ping");
// Address refresh broadcast // Address refresh broadcast
static int64 nLastRebroadcast; static int64 nLastRebroadcast;
if (nLastRebroadcast < GetTime() - 24 * 60 * 60) // every 24 hours if (GetTime() - nLastRebroadcast > 24 * 60 * 60) // every 24 hours
{ {
nLastRebroadcast = GetTime(); nLastRebroadcast = GetTime();
CRITICAL_BLOCK(cs_vNodes) CRITICAL_BLOCK(cs_vNodes)
@ -2194,9 +2214,16 @@ bool SendMessages(CNode* pto)
} }
} }
// Keep-alive ping // Clear inventory known periodically in case an inv message was missed,
if (pto->nLastSend && GetTime() - pto->nLastSend > 12 * 60 && pto->vSend.empty()) // although usually they would just get it from another node.
pto->PushMessage("ping"); static int64 nLastInventoryKnownClear;
if (GetTime() - nLastInventoryKnownClear > 2 * 60 * 60) // every 2 hours
{
nLastInventoryKnownClear = GetTime();
CRITICAL_BLOCK(cs_vNodes)
foreach(CNode* pnode, vNodes)
pnode->setInventoryKnown.clear();
}
// //
@ -2243,7 +2270,6 @@ bool SendMessages(CNode* pto)
} }
} }
pto->vInventoryToSend.clear(); pto->vInventoryToSend.clear();
pto->setInventoryKnown2.clear();
} }
if (!vInventoryToSend.empty()) if (!vInventoryToSend.empty())
pto->PushMessage("inv", vInventoryToSend); pto->PushMessage("inv", vInventoryToSend);
@ -2817,8 +2843,7 @@ bool CommitTransactionSpent(const CWalletTx& wtxNew, const CKey& key)
// This is only to keep the database open to defeat the auto-flush for the // This is only to keep the database open to defeat the auto-flush for the
// duration of this scope. This is the only place where this optimization // duration of this scope. This is the only place where this optimization
// maybe makes sense; please don't do it anywhere else. Keeping databases // maybe makes sense; please don't do it anywhere else.
// open longer than necessary can create deadlocks.
CWalletDB walletdb("r"); CWalletDB walletdb("r");
// Add the change's private key to wallet // Add the change's private key to wallet

10
main.h
View File

@ -1009,9 +1009,9 @@ public:
void print() const void print() const
{ {
printf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%d)\n", printf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%d)\n",
GetHash().ToString().substr(0,14).c_str(), GetHash().ToString().substr(0,16).c_str(),
nVersion, nVersion,
hashPrevBlock.ToString().substr(0,14).c_str(), hashPrevBlock.ToString().substr(0,16).c_str(),
hashMerkleRoot.ToString().substr(0,6).c_str(), hashMerkleRoot.ToString().substr(0,6).c_str(),
nTime, nBits, nNonce, nTime, nBits, nNonce,
vtx.size()); vtx.size());
@ -1159,7 +1159,7 @@ public:
return strprintf("CBlockIndex(nprev=%08x, pnext=%08x, nFile=%d, nBlockPos=%-6d nHeight=%d, merkle=%s, hashBlock=%s)", return strprintf("CBlockIndex(nprev=%08x, pnext=%08x, nFile=%d, nBlockPos=%-6d nHeight=%d, merkle=%s, hashBlock=%s)",
pprev, pnext, nFile, nBlockPos, nHeight, pprev, pnext, nFile, nBlockPos, nHeight,
hashMerkleRoot.ToString().substr(0,6).c_str(), hashMerkleRoot.ToString().substr(0,6).c_str(),
GetBlockHash().ToString().substr(0,14).c_str()); GetBlockHash().ToString().substr(0,16).c_str());
} }
void print() const void print() const
@ -1229,8 +1229,8 @@ public:
str += CBlockIndex::ToString(); str += CBlockIndex::ToString();
str += strprintf("\n hashBlock=%s, hashPrev=%s, hashNext=%s)", str += strprintf("\n hashBlock=%s, hashPrev=%s, hashNext=%s)",
GetBlockHash().ToString().c_str(), GetBlockHash().ToString().c_str(),
hashPrev.ToString().substr(0,14).c_str(), hashPrev.ToString().substr(0,16).c_str(),
hashNext.ToString().substr(0,14).c_str()); hashNext.ToString().substr(0,16).c_str());
return str; return str;
} }

View File

@ -17,24 +17,21 @@ endif
INCLUDEPATHS= \ INCLUDEPATHS= \
-I"/usr/include" \ -I"/usr/include" \
-I"/usr/local/boost_1_40_0" \
-I"/usr/local/db-4.7.25.NC/build_unix" \
-I"/usr/local/include/wx-2.8" \ -I"/usr/local/include/wx-2.8" \
-I"/usr/local/lib/wx/include/gtk2-ansi-debug-static-2.8" -I"/usr/local/lib/wx/include/gtk2-ansi-debug-static-2.8"
LIBPATHS= \ LIBPATHS= \
-L"/usr/lib" \ -L"/usr/lib" \
-L"/usr/local/lib" \ -L"/usr/local/lib" \
-L"/usr/local/db-4.7.25.NC/build_unix"
LIBS= \ LIBS= \
-Wl,-Bstatic -l boost_thread -l boost_system -l boost_filesystem -Wl,-Bdynamic \ -Wl,-Bstatic -l boost_system -l boost_filesystem -Wl,-Bdynamic \
-Wl,-Bstatic -l db_cxx -l wx_gtk2$(D)-2.8 -Wl,-Bdynamic \ -Wl,-Bstatic -l db_cxx -l wx_gtk2$(D)-2.8 -Wl,-Bdynamic \
-l crypto \ -l crypto \
-l gtk-x11-2.0 -l gthread-2.0 -l SM -l gtk-x11-2.0 -l gthread-2.0 -l SM
WXDEFS=-D__WXGTK__ -DNOPCH WXDEFS=-D__WXGTK__ -DNOPCH
CFLAGS=-O0 -w -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(WXDEFS) $(INCLUDEPATHS) CFLAGS=-O0 -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(WXDEFS) $(INCLUDEPATHS)
HEADERS=headers.h util.h main.h serialize.h uint256.h key.h bignum.h script.h db.h base58.h HEADERS=headers.h util.h main.h serialize.h uint256.h key.h bignum.h script.h db.h base58.h

110
net.cpp
View File

@ -148,8 +148,8 @@ bool GetMyExternalIP2(const CAddress& addrConnect, const char* pszGet, const cha
bool GetMyExternalIP(unsigned int& ipRet) bool GetMyExternalIP(unsigned int& ipRet)
{ {
CAddress addrConnect; CAddress addrConnect;
char* pszGet; const char* pszGet;
char* pszKeyword; const char* pszKeyword;
if (fUseProxy) if (fUseProxy)
return false; return false;
@ -463,14 +463,21 @@ CNode* ConnectNode(CAddress addrConnect, int64 nTimeout)
} }
} }
void CNode::DoDisconnect() void CNode::CloseSocketDisconnect()
{ {
if (fDebug) fDisconnect = true;
printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str()); if (hSocket != INVALID_SOCKET)
printf("disconnecting node %s\n", addr.ToStringLog().c_str()); {
if (fDebug)
closesocket(hSocket); printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
printf("disconnecting node %s\n", addr.ToStringLog().c_str());
closesocket(hSocket);
hSocket = INVALID_SOCKET;
}
}
void CNode::Cleanup()
{
// All of a nodes broadcasts and subscriptions are automatically torn down // All of a nodes broadcasts and subscriptions are automatically torn down
// when it goes down, so a node has to stay up to keep its broadcast going. // when it goes down, so a node has to stay up to keep its broadcast going.
@ -540,11 +547,12 @@ void ThreadSocketHandler2(void* parg)
// remove from vNodes // remove from vNodes
vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end()); vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end());
// close socket // close socket and cleanup
pnode->DoDisconnect(); pnode->CloseSocketDisconnect();
pnode->Cleanup();
// hold in disconnected pool until all refs are released // hold in disconnected pool until all refs are released
pnode->nReleaseTime = max(pnode->nReleaseTime, GetTime() + 5 * 60); pnode->nReleaseTime = max(pnode->nReleaseTime, GetTime() + 15 * 60);
if (pnode->fNetworkNode || pnode->fInbound) if (pnode->fNetworkNode || pnode->fInbound)
pnode->Release(); pnode->Release();
vNodesDisconnected.push_back(pnode); vNodesDisconnected.push_back(pnode);
@ -599,6 +607,8 @@ void ThreadSocketHandler2(void* parg)
{ {
foreach(CNode* pnode, vNodes) foreach(CNode* pnode, vNodes)
{ {
if (pnode->hSocket == INVALID_SOCKET || pnode->hSocket < 0)
continue;
FD_SET(pnode->hSocket, &fdsetRecv); FD_SET(pnode->hSocket, &fdsetRecv);
FD_SET(pnode->hSocket, &fdsetError); FD_SET(pnode->hSocket, &fdsetError);
hSocketMax = max(hSocketMax, pnode->hSocket); hSocketMax = max(hSocketMax, pnode->hSocket);
@ -659,17 +669,22 @@ void ThreadSocketHandler2(void* parg)
// //
vector<CNode*> vNodesCopy; vector<CNode*> vNodesCopy;
CRITICAL_BLOCK(cs_vNodes) CRITICAL_BLOCK(cs_vNodes)
{
vNodesCopy = vNodes; vNodesCopy = vNodes;
foreach(CNode* pnode, vNodesCopy)
pnode->AddRef();
}
foreach(CNode* pnode, vNodesCopy) foreach(CNode* pnode, vNodesCopy)
{ {
if (fShutdown) if (fShutdown)
return; return;
SOCKET hSocket = pnode->hSocket;
// //
// Receive // Receive
// //
if (FD_ISSET(hSocket, &fdsetRecv) || FD_ISSET(hSocket, &fdsetError)) if (pnode->hSocket == INVALID_SOCKET)
continue;
if (FD_ISSET(pnode->hSocket, &fdsetRecv) || FD_ISSET(pnode->hSocket, &fdsetError))
{ {
TRY_CRITICAL_BLOCK(pnode->cs_vRecv) TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
{ {
@ -678,7 +693,7 @@ void ThreadSocketHandler2(void* parg)
// typical socket buffer is 8K-64K // typical socket buffer is 8K-64K
char pchBuf[0x10000]; char pchBuf[0x10000];
int nBytes = recv(hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT); int nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT);
if (nBytes > 0) if (nBytes > 0)
{ {
vRecv.resize(nPos + nBytes); vRecv.resize(nPos + nBytes);
@ -690,7 +705,7 @@ void ThreadSocketHandler2(void* parg)
// socket closed gracefully // socket closed gracefully
if (!pnode->fDisconnect) if (!pnode->fDisconnect)
printf("socket closed\n"); printf("socket closed\n");
pnode->fDisconnect = true; pnode->CloseSocketDisconnect();
} }
else if (nBytes < 0) else if (nBytes < 0)
{ {
@ -700,7 +715,7 @@ void ThreadSocketHandler2(void* parg)
{ {
if (!pnode->fDisconnect) if (!pnode->fDisconnect)
printf("socket recv error %d\n", nErr); printf("socket recv error %d\n", nErr);
pnode->fDisconnect = true; pnode->CloseSocketDisconnect();
} }
} }
} }
@ -709,14 +724,16 @@ void ThreadSocketHandler2(void* parg)
// //
// Send // Send
// //
if (FD_ISSET(hSocket, &fdsetSend)) if (pnode->hSocket == INVALID_SOCKET)
continue;
if (FD_ISSET(pnode->hSocket, &fdsetSend))
{ {
TRY_CRITICAL_BLOCK(pnode->cs_vSend) TRY_CRITICAL_BLOCK(pnode->cs_vSend)
{ {
CDataStream& vSend = pnode->vSend; CDataStream& vSend = pnode->vSend;
if (!vSend.empty()) if (!vSend.empty())
{ {
int nBytes = send(hSocket, &vSend[0], vSend.size(), MSG_NOSIGNAL | MSG_DONTWAIT); int nBytes = send(pnode->hSocket, &vSend[0], vSend.size(), MSG_NOSIGNAL | MSG_DONTWAIT);
if (nBytes > 0) if (nBytes > 0)
{ {
vSend.erase(vSend.begin(), vSend.begin() + nBytes); vSend.erase(vSend.begin(), vSend.begin() + nBytes);
@ -729,7 +746,7 @@ void ThreadSocketHandler2(void* parg)
if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS) if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
{ {
printf("socket send error %d\n", nErr); printf("socket send error %d\n", nErr);
pnode->fDisconnect = true; pnode->CloseSocketDisconnect();
} }
} }
} }
@ -760,18 +777,12 @@ void ThreadSocketHandler2(void* parg)
} }
} }
} }
CRITICAL_BLOCK(cs_vNodes)
//// debug heartbeat
static int64 nHeartbeat1;
if (GetTime() - nHeartbeat1 >= 5 * 60)
{ {
printf("%s sendrecv\n", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str()); foreach(CNode* pnode, vNodesCopy)
nHeartbeat1 = GetTime(); pnode->Release();
fDebug = true;
} }
nThreadSocketHandlerHeartbeat = GetTime(); nThreadSocketHandlerHeartbeat = GetTime();
Sleep(10); Sleep(10);
} }
@ -812,18 +823,21 @@ void ThreadOpenConnections2(void* parg)
printf("ThreadOpenConnections started\n"); printf("ThreadOpenConnections started\n");
// Connect to specific addresses // Connect to specific addresses
while (mapArgs.count("-connect")) if (mapArgs.count("-connect"))
{ {
foreach(string strAddr, mapMultiArgs["-connect"]) for (int64 nLoop = 0;; nLoop++)
{ {
CAddress addr(strAddr, NODE_NETWORK); foreach(string strAddr, mapMultiArgs["-connect"])
if (addr.IsValid())
OpenNetworkConnection(addr);
for (int i = 0; i < 10; i++)
{ {
Sleep(1000); CAddress addr(strAddr, NODE_NETWORK);
if (fShutdown) if (addr.IsValid())
return; OpenNetworkConnection(addr);
for (int i = 0; i < 10 && i < nLoop; i++)
{
Sleep(500);
if (fShutdown)
return;
}
} }
} }
} }
@ -837,7 +851,7 @@ void ThreadOpenConnections2(void* parg)
if (addr.IsValid()) if (addr.IsValid())
{ {
OpenNetworkConnection(addr); OpenNetworkConnection(addr);
Sleep(1000); Sleep(500);
if (fShutdown) if (fShutdown)
return; return;
} }
@ -898,7 +912,7 @@ void ThreadOpenConnections2(void* parg)
// 30 days 27 hours // 30 days 27 hours
// 90 days 46 hours // 90 days 46 hours
// 365 days 93 hours // 365 days 93 hours
int64 nDelay = 3600.0 * sqrt(fabs(nSinceLastSeen) / 3600.0) + nRandomizer; int64 nDelay = (int64)(3600.0 * sqrt(fabs(nSinceLastSeen) / 3600.0) + nRandomizer);
// Fast reconnect for one hour after last seen // Fast reconnect for one hour after last seen
if (nSinceLastSeen < 60 * 60) if (nSinceLastSeen < 60 * 60)
@ -1013,11 +1027,13 @@ void ThreadMessageHandler2(void* parg)
// Poll the connected nodes for messages // Poll the connected nodes for messages
vector<CNode*> vNodesCopy; vector<CNode*> vNodesCopy;
CRITICAL_BLOCK(cs_vNodes) CRITICAL_BLOCK(cs_vNodes)
{
vNodesCopy = vNodes; vNodesCopy = vNodes;
foreach(CNode* pnode, vNodesCopy)
pnode->AddRef();
}
foreach(CNode* pnode, vNodesCopy) foreach(CNode* pnode, vNodesCopy)
{ {
pnode->AddRef();
// Receive messages // Receive messages
TRY_CRITICAL_BLOCK(pnode->cs_vRecv) TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
ProcessMessages(pnode); ProcessMessages(pnode);
@ -1029,8 +1045,11 @@ void ThreadMessageHandler2(void* parg)
SendMessages(pnode); SendMessages(pnode);
if (fShutdown) if (fShutdown)
return; return;
}
pnode->Release(); CRITICAL_BLOCK(cs_vNodes)
{
foreach(CNode* pnode, vNodesCopy)
pnode->Release();
} }
// Wait and allow messages to bunch up // Wait and allow messages to bunch up
@ -1257,8 +1276,7 @@ void StartNode(void* parg)
if (!fGot) if (!fGot)
{ {
printf("*** closing socket\n"); printf("*** closing socket\n");
closesocket(pnode->hSocket); pnode->CloseSocketDisconnect();
pnode->fDisconnect = true;
} }
} }
} }
@ -1292,7 +1310,7 @@ bool StopNode()
int64 nStart = GetTime(); int64 nStart = GetTime();
while (vnThreadsRunning[0] > 0 || vnThreadsRunning[2] > 0 || vnThreadsRunning[3] > 0) while (vnThreadsRunning[0] > 0 || vnThreadsRunning[2] > 0 || vnThreadsRunning[3] > 0)
{ {
if (GetTime() - nStart > 15) if (GetTime() - nStart > 20)
break; break;
Sleep(20); Sleep(20);
} }

16
net.h
View File

@ -414,7 +414,7 @@ public:
string ToString() const string ToString() const
{ {
return strprintf("%s %s", GetCommand(), hash.ToString().substr(0,14).c_str()); return strprintf("%s %s", GetCommand(), hash.ToString().substr(0,16).c_str());
} }
void print() const void print() const
@ -504,6 +504,7 @@ public:
int64 nReleaseTime; int64 nReleaseTime;
map<uint256, CRequestTracker> mapRequests; map<uint256, CRequestTracker> mapRequests;
CCriticalSection cs_mapRequests; CCriticalSection cs_mapRequests;
uint256 hashContinue;
// flood // flood
vector<CAddress> vAddrToSend; vector<CAddress> vAddrToSend;
@ -512,7 +513,6 @@ public:
// inventory based relay // inventory based relay
set<CInv> setInventoryKnown; set<CInv> setInventoryKnown;
set<CInv> setInventoryKnown2;
vector<CInv> vInventoryToSend; vector<CInv> vInventoryToSend;
CCriticalSection cs_inventory; CCriticalSection cs_inventory;
multimap<int64, CInv> mapAskFor; multimap<int64, CInv> mapAskFor;
@ -541,6 +541,7 @@ public:
fDisconnect = false; fDisconnect = false;
nRefCount = 0; nRefCount = 0;
nReleaseTime = 0; nReleaseTime = 0;
hashContinue = 0;
fGetAddr = false; fGetAddr = false;
vfSubscribe.assign(256, false); vfSubscribe.assign(256, false);
@ -550,13 +551,16 @@ public:
CAddress addrYou = (fUseProxy ? CAddress("0.0.0.0") : addr); CAddress addrYou = (fUseProxy ? CAddress("0.0.0.0") : addr);
CAddress addrMe = (fUseProxy ? CAddress("0.0.0.0") : addrLocalHost); CAddress addrMe = (fUseProxy ? CAddress("0.0.0.0") : addrLocalHost);
RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce)); RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));
PushMessage("version", VERSION, nLocalServices, nTime, addrYou, addrMe, nLocalHostNonce, string("test5")); PushMessage("version", VERSION, nLocalServices, nTime, addrYou, addrMe, nLocalHostNonce, string(pszSubVer));
} }
~CNode() ~CNode()
{ {
if (hSocket != INVALID_SOCKET) if (hSocket != INVALID_SOCKET)
{
closesocket(hSocket); closesocket(hSocket);
hSocket = INVALID_SOCKET;
}
} }
private: private:
@ -570,12 +574,13 @@ public:
return max(nRefCount, 0) + (GetTime() < nReleaseTime ? 1 : 0); return max(nRefCount, 0) + (GetTime() < nReleaseTime ? 1 : 0);
} }
void AddRef(int64 nTimeout=0) CNode* AddRef(int64 nTimeout=0)
{ {
if (nTimeout != 0) if (nTimeout != 0)
nReleaseTime = max(nReleaseTime, GetTime() + nTimeout); nReleaseTime = max(nReleaseTime, GetTime() + nTimeout);
else else
nRefCount++; nRefCount++;
return this;
} }
void Release() void Release()
@ -899,7 +904,8 @@ public:
bool IsSubscribed(unsigned int nChannel); bool IsSubscribed(unsigned int nChannel);
void Subscribe(unsigned int nChannel, unsigned int nHops=0); void Subscribe(unsigned int nChannel, unsigned int nHops=0);
void CancelSubscribe(unsigned int nChannel); void CancelSubscribe(unsigned int nChannel);
void DoDisconnect(); void CloseSocketDisconnect();
void Cleanup();
}; };

View File

@ -20,6 +20,7 @@ class CDataStream;
class CAutoFile; class CAutoFile;
static const int VERSION = 106; static const int VERSION = 106;
static const char* pszSubVer = " linux-test8";

27
ui.cpp
View File

@ -1664,7 +1664,7 @@ void COptionsDialog::OnButtonApply(wxCommandEvent& event)
CAboutDialog::CAboutDialog(wxWindow* parent) : CAboutDialogBase(parent) CAboutDialog::CAboutDialog(wxWindow* parent) : CAboutDialogBase(parent)
{ {
m_staticTextVersion->SetLabel(strprintf("version 0.%d.%d Beta", VERSION/100, VERSION%100)); m_staticTextVersion->SetLabel(strprintf("version 0.%d.%d beta", VERSION/100, VERSION%100));
// Workaround until upgrade to wxWidgets supporting UTF-8 // Workaround until upgrade to wxWidgets supporting UTF-8
wxString str = m_staticTextMain->GetLabel(); wxString str = m_staticTextMain->GetLabel();
@ -2030,7 +2030,7 @@ void CSendingDialog::StartTransfer()
// We may have connected already for product details // We may have connected already for product details
if (!Status("Connecting...")) if (!Status("Connecting..."))
return; return;
CNode* pnode = ConnectNode(addr, 5 * 60); CNode* pnode = ConnectNode(addr, 15 * 60);
if (!pnode) if (!pnode)
{ {
Error("Unable to connect"); Error("Unable to connect");
@ -2075,14 +2075,6 @@ void CSendingDialog::OnReply2(CDataStream& vRecv)
return; return;
} }
// Should already be connected
CNode* pnode = ConnectNode(addr, 5 * 60);
if (!pnode)
{
Error("Lost connection");
return;
}
// Pause to give the user a chance to cancel // Pause to give the user a chance to cancel
while (wxDateTime::UNow() < start + wxTimeSpan(0, 0, 0, 2 * 1000)) while (wxDateTime::UNow() < start + wxTimeSpan(0, 0, 0, 2 * 1000))
{ {
@ -2112,6 +2104,14 @@ void CSendingDialog::OnReply2(CDataStream& vRecv)
return; return;
} }
// Make sure we're still connected
CNode* pnode = ConnectNode(addr, 2 * 60 * 60);
if (!pnode)
{
Error("Lost connection, transaction cancelled");
return;
}
// Last chance to cancel // Last chance to cancel
Sleep(50); Sleep(50);
if (!Status()) if (!Status())
@ -3495,12 +3495,14 @@ bool CMyApp::OnInit2()
if (mapArgs.count("-debug")) if (mapArgs.count("-debug"))
fDebug = true; fDebug = true;
if (strstr(pszSubVer, "test"))
fDebug = true;
if (mapArgs.count("-printtodebugger")) if (mapArgs.count("-printtodebugger"))
fPrintToDebugger = true; fPrintToDebugger = true;
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");
printf("Bitcoin version %d, OS version %s\n", VERSION, wxGetOsDescription().mb_str()); printf("Bitcoin version %d%s, OS version %s\n", VERSION, pszSubVer, wxGetOsDescription().mb_str());
if (mapArgs.count("-loadblockindextest")) if (mapArgs.count("-loadblockindextest"))
{ {
@ -3843,9 +3845,8 @@ void SetStartOnSystemStartup(bool fAutoStart)
CoInitialize(NULL); CoInitialize(NULL);
// Get a pointer to the IShellLink interface. // Get a pointer to the IShellLink interface.
HRESULT hres = NULL;
IShellLink* psl = NULL; IShellLink* psl = NULL;
hres = CoCreateInstance(CLSID_ShellLink, NULL, HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL,
CLSCTX_INPROC_SERVER, IID_IShellLink, CLSCTX_INPROC_SERVER, IID_IShellLink,
reinterpret_cast<void**>(&psl)); reinterpret_cast<void**>(&psl));

View File

@ -56,9 +56,11 @@ public:
// Close sockets // Close sockets
foreach(CNode* pnode, vNodes) foreach(CNode* pnode, vNodes)
closesocket(pnode->hSocket); if (pnode->hSocket != INVALID_SOCKET)
if (closesocket(hListenSocket) == SOCKET_ERROR) closesocket(pnode->hSocket);
printf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError()); if (hListenSocket != INVALID_SOCKET)
if (closesocket(hListenSocket) == SOCKET_ERROR)
printf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError());
#ifdef __WXMSW__ #ifdef __WXMSW__
// Shutdown Windows Sockets // Shutdown Windows Sockets
@ -348,7 +350,7 @@ void ParseParameters(int argc, char* argv[])
{ {
char psz[10000]; char psz[10000];
strlcpy(psz, argv[i], sizeof(psz)); strlcpy(psz, argv[i], sizeof(psz));
char* pszValue = ""; char* pszValue = (char*)"";
if (strchr(psz, '=')) if (strchr(psz, '='))
{ {
pszValue = strchr(psz, '='); pszValue = strchr(psz, '=');

23
util.h
View File

@ -57,9 +57,11 @@ inline T& REF(const T& val)
#ifdef __WXMSW__ #ifdef __WXMSW__
#define MSG_NOSIGNAL 0 #define MSG_NOSIGNAL 0
#define MSG_DONTWAIT 0 #define MSG_DONTWAIT 0
#ifndef UINT64_MAX
#define UINT64_MAX _UI64_MAX #define UINT64_MAX _UI64_MAX
#define INT64_MAX _I64_MAX #define INT64_MAX _I64_MAX
#define INT64_MIN _I64_MIN #define INT64_MIN _I64_MIN
#endif
#else #else
#define WSAGetLastError() errno #define WSAGetLastError() errno
#define WSAEWOULDBLOCK EWOULDBLOCK #define WSAEWOULDBLOCK EWOULDBLOCK
@ -67,7 +69,7 @@ inline T& REF(const T& val)
#define WSAEINTR EINTR #define WSAEINTR EINTR
#define WSAEINPROGRESS EINPROGRESS #define WSAEINPROGRESS EINPROGRESS
#define WSAEADDRINUSE EADDRINUSE #define WSAEADDRINUSE EADDRINUSE
#define closesocket(s) close(s) #define WSAENOTSOCK EBADF
#define INVALID_SOCKET (SOCKET)(~0) #define INVALID_SOCKET (SOCKET)(~0)
#define SOCKET_ERROR -1 #define SOCKET_ERROR -1
typedef u_int SOCKET; typedef u_int SOCKET;
@ -80,6 +82,23 @@ typedef u_int SOCKET;
#define Beep(n1,n2) (0) #define Beep(n1,n2) (0)
#endif #endif
inline int myclosesocket(SOCKET& hSocket)
{
if (hSocket == INVALID_SOCKET)
return WSAENOTSOCK;
#ifdef __WXMSW__
int ret = closesocket(hSocket);
#else
int ret = close(hSocket);
#endif
hSocket = INVALID_SOCKET;
return ret;
}
#define closesocket(s) myclosesocket(s)
@ -149,7 +168,7 @@ public:
bool TryEnter() { return mutex.TryLock() == wxMUTEX_NO_ERROR; } bool TryEnter() { return mutex.TryLock() == wxMUTEX_NO_ERROR; }
#endif #endif
public: public:
char* pszFile; const char* pszFile;
int nLine; int nLine;
}; };

View File

@ -1,5 +1,5 @@
/* XPM */ /* XPM */
static char * addressbook16_xpm[] = { static const char * addressbook16_xpm[] = {
/* columns rows colors chars-per-pixel */ /* columns rows colors chars-per-pixel */
"16 16 256 2", "16 16 256 2",
" c #FFFFFF", " c #FFFFFF",

View File

@ -1,5 +1,5 @@
/* XPM */ /* XPM */
static char * addressbook20_xpm[] = { static const char * addressbook20_xpm[] = {
/* columns rows colors chars-per-pixel */ /* columns rows colors chars-per-pixel */
"20 20 256 2", "20 20 256 2",
" c #FFFFFF", " c #FFFFFF",

View File

@ -1,5 +1,5 @@
/* XPM */ /* XPM */
static char * bitcoin16_xpm[] = { static const char * bitcoin16_xpm[] = {
/* columns rows colors chars-per-pixel */ /* columns rows colors chars-per-pixel */
"16 16 181 2", "16 16 181 2",
" c #775605", " c #775605",

View File

@ -1,5 +1,5 @@
/* XPM */ /* XPM */
static char * bitcoin20_xpm[] = { static const char * bitcoin20_xpm[] = {
/* columns rows colors chars-per-pixel */ /* columns rows colors chars-per-pixel */
"20 20 200 2", "20 20 200 2",
" c #7B5500", " c #7B5500",

View File

@ -1,5 +1,5 @@
/* XPM */ /* XPM */
static char * bitcoin32_xpm[] = { static const char * bitcoin32_xpm[] = {
/* columns rows colors chars-per-pixel */ /* columns rows colors chars-per-pixel */
"32 32 185 2", "32 32 185 2",
" c #715103", " c #715103",

View File

@ -1,5 +1,5 @@
/* XPM */ /* XPM */
static char * bitcoin48_xpm[] = { static const char * bitcoin48_xpm[] = {
/* columns rows colors chars-per-pixel */ /* columns rows colors chars-per-pixel */
"48 48 224 2", "48 48 224 2",
" c #715103", " c #715103",

View File

@ -1,5 +1,5 @@
/* XPM */ /* XPM */
static char * check_xpm[] = { static const char * check_xpm[] = {
/* columns rows colors chars-per-pixel */ /* columns rows colors chars-per-pixel */
"32 32 3 1", "32 32 3 1",
" c #008000", " c #008000",

View File

@ -1,5 +1,5 @@
/* XPM */ /* XPM */
static char * send16_xpm[] = { static const char * send16_xpm[] = {
/* columns rows colors chars-per-pixel */ /* columns rows colors chars-per-pixel */
"16 16 256 2", "16 16 256 2",
" c #ADF7AD", " c #ADF7AD",

View File

@ -1,5 +1,5 @@
/* XPM */ /* XPM */
static char * send16noshadow_xpm[] = { static const char * send16noshadow_xpm[] = {
/* columns rows colors chars-per-pixel */ /* columns rows colors chars-per-pixel */
"16 16 256 2", "16 16 256 2",
" c #ADF7AD", " c #ADF7AD",

View File

@ -1,5 +1,5 @@
/* XPM */ /* XPM */
static char * send20_xpm[] = { static const char * send20_xpm[] = {
/* columns rows colors chars-per-pixel */ /* columns rows colors chars-per-pixel */
"20 20 256 2", "20 20 256 2",
" c #CEFFCE", " c #CEFFCE",