src/qt/aboutdialog.h \
src/qt/editaddressdialog.h \
src/qt/bitcoinaddressvalidator.h \
+ src/addrman.h \
src/base58.h \
src/bignum.h \
src/checkpoints.h \
src/init.h \
src/headers.h \
src/irc.h \
+ src/mruset.h \
src/json/json_spirit_writer_template.h \
src/json/json_spirit_writer.h \
src/json/json_spirit_value.h \
src/net.cpp \
src/irc.cpp \
src/checkpoints.cpp \
+ src/addrman.cpp \
src/db.cpp \
src/json/json_spirit_writer.cpp \
src/json/json_spirit_value.cpp \
TRANSLATIONS = $$files(src/qt/locale/bitcoin_*.ts)
isEmpty(QMAKE_LRELEASE) {
- win32:QMAKE_LRELEASE = $$[QT_INSTALL_BINS]\lrelease.exe
+ win32:QMAKE_LRELEASE = $$[QT_INSTALL_BINS]\\lrelease.exe
else:QMAKE_LRELEASE = $$[QT_INSTALL_BINS]/lrelease
}
isEmpty(TS_DIR):TS_DIR = src/qt/locale
macx:BOOST_INCLUDE_PATH = /opt/local/include
}
-windows:LIBS += -lws2_32 -lshlwapi
-windows:DEFINES += WIN32
+windows:LIBS += -lmingwthrd -lws2_32 -lshlwapi
+windows:DEFINES += _MT WIN32
windows:RC_FILE = src/qt/res/bitcoin-qt.rc
!windows:!mac {
DEFINES += LINUX
+ LIBS += -lrt
}
macx:HEADERS += src/qt/macdockiconhandler.h
LIBS += $$join(BOOST_LIB_PATH,,-L,) $$join(BDB_LIB_PATH,,-L,) $$join(OPENSSL_LIB_PATH,,-L,) $$join(QRENCODE_LIB_PATH,,-L,)
LIBS += -lssl -lcrypto -ldb_cxx$$BDB_LIB_SUFFIX
# -lgdi32 has to happen after -lcrypto (see #681)
-windows:LIBS += -lgdi32
+windows:LIBS += -lole32 -luuid -lgdi32
LIBS += -lboost_system$$BOOST_LIB_SUFFIX -lboost_filesystem$$BOOST_LIB_SUFFIX -lboost_program_options$$BOOST_LIB_SUFFIX -lboost_thread$$BOOST_THREAD_LIB_SUFFIX
contains(RELEASE, 1) {
string strErrorFile = strDataDir + "/db.log";
printf("dbenv.open strLogDir=%s strErrorFile=%s\n", strLogDir.c_str(), strErrorFile.c_str());
+ int nDbCache = GetArg("-dbcache", 25);
dbenv.set_lg_dir(strLogDir.c_str());
- dbenv.set_lg_max(10000000);
+ dbenv.set_cachesize(nDbCache / 1024, (nDbCache % 1024)*1048576, 1);
+ dbenv.set_lg_bsize(10485760);
+ dbenv.set_lg_max(104857600);
dbenv.set_lk_max_locks(10000);
dbenv.set_lk_max_objects(10000);
dbenv.set_errfile(fopen(strErrorFile.c_str(), "a")); /// debug
nMinutes = 1;
if (strFile == "addr.dat")
nMinutes = 2;
- if (strFile == "blkindex.dat" && IsInitialBlockDownload() && nBestHeight % 500 != 0)
+ if (strFile == "blkindex.dat" && IsInitialBlockDownload() && nBestHeight % 5000 != 0)
nMinutes = 1;
dbenv.txn_checkpoint(0, nMinutes, 0);
return Write(make_pair(string("addr"), addr.GetKey()), addr);
}
+ bool CAddrDB::WriteAddrman(const CAddrMan& addrman)
+ {
+ return Write(string("addrman"), addrman);
+ }
+
bool CAddrDB::EraseAddress(const CAddress& addr)
{
return Erase(make_pair(string("addr"), addr.GetKey()));
}
- bool CAddrDB::LoadAddresses()
+ bool CAddrDB::LoadAddresses(bool &fUpdate)
{
- CRITICAL_BLOCK(cs_mapAddresses)
+ bool fAddrMan = false;
+ if (Read(string("addrman"), addrman))
{
- // Get cursor
- Dbc* pcursor = GetCursor();
- if (!pcursor)
+ printf("Loaded %i addresses\n", addrman.size());
+ fAddrMan = true;
+ }
+
+ vector<CAddress> vAddr;
+
+ // Get cursor
+ Dbc* pcursor = GetCursor();
+ if (!pcursor)
+ return false;
+
+ loop
+ {
+ // Read next record
+ CDataStream ssKey;
+ CDataStream ssValue;
+ int ret = ReadAtCursor(pcursor, ssKey, ssValue);
+ if (ret == DB_NOTFOUND)
+ break;
+ else if (ret != 0)
return false;
- loop
+ // Unserialize
+ string strType;
+ ssKey >> strType;
+ if (strType == "addr")
{
- // Read next record
- CDataStream ssKey;
- CDataStream ssValue;
- int ret = ReadAtCursor(pcursor, ssKey, ssValue);
- if (ret == DB_NOTFOUND)
- break;
- else if (ret != 0)
- return false;
-
- // Unserialize
- string strType;
- ssKey >> strType;
- if (strType == "addr")
+ if (fAddrMan)
+ fUpdate = true;
+ else
{
CAddress addr;
ssValue >> addr;
- mapAddresses.insert(make_pair(addr.GetKey(), addr));
+ vAddr.push_back(addr);
}
+
}
- pcursor->close();
+ }
+ pcursor->close();
- printf("Loaded %d addresses\n", mapAddresses.size());
+ if (!fAddrMan)
+ {
+ addrman.Add(vAddr, CNetAddr("0.0.0.0"));
+ printf("Loaded %i addresses\n", addrman.size());
}
return true;
bool LoadAddresses()
{
- return CAddrDB("cr+").LoadAddresses();
+ bool fUpdate = false;
+ bool fRet = CAddrDB("cr+").LoadAddresses(fUpdate);
+ if (fUpdate)
+ CDB::Rewrite("addr.dat", "\004addr");
+ return fRet;
}
vector<uint256> vWalletUpgrade;
bool fIsEncrypted = false;
- // Modify defaults
-#ifndef WIN32
- // Tray icon sometimes disappears on 9.10 karmic koala 64-bit, leaving no way to access the program
- fMinimizeToTray = false;
- fMinimizeOnClose = false;
-#endif
-
//// todo: shouldn't we catch exceptions and try to recover and continue?
CRITICAL_BLOCK(pwallet->cs_wallet)
{
// Get cursor
Dbc* pcursor = GetCursor();
if (!pcursor)
+ {
+ printf("Error getting wallet database cursor\n");
return DB_CORRUPT;
+ }
loop
{
if (ret == DB_NOTFOUND)
break;
else if (ret != 0)
+ {
+ printf("Error reading next record from wallet database\n");
return DB_CORRUPT;
+ }
// Unserialize
// Taking advantage of the fact that pair serialization
ssValue >> pkey;
key.SetPubKey(vchPubKey);
key.SetPrivKey(pkey);
- if (key.GetPubKey() != vchPubKey || !key.IsValid())
+ if (key.GetPubKey() != vchPubKey)
+ {
+ printf("Error reading wallet database: CPrivKey pubkey inconsistency\n");
return DB_CORRUPT;
+ }
+ if (!key.IsValid())
+ {
+ printf("Error reading wallet database: invalid CPrivKey\n");
+ return DB_CORRUPT;
+ }
}
else
{
ssValue >> wkey;
key.SetPubKey(vchPubKey);
key.SetPrivKey(wkey.vchPrivKey);
- if (key.GetPubKey() != vchPubKey || !key.IsValid())
+ if (key.GetPubKey() != vchPubKey)
+ {
+ printf("Error reading wallet database: CWalletKey pubkey inconsistency\n");
return DB_CORRUPT;
+ }
+ if (!key.IsValid())
+ {
+ printf("Error reading wallet database: invalid CWalletKey\n");
+ return DB_CORRUPT;
+ }
}
if (!pwallet->LoadKey(key))
+ {
+ printf("Error reading wallet database: LoadKey failed\n");
return DB_CORRUPT;
+ }
}
else if (strType == "mkey")
{
CMasterKey kMasterKey;
ssValue >> kMasterKey;
if(pwallet->mapMasterKeys.count(nID) != 0)
+ {
+ printf("Error reading wallet database: duplicate CMasterKey id %u\n", nID);
return DB_CORRUPT;
+ }
pwallet->mapMasterKeys[nID] = kMasterKey;
if (pwallet->nMasterKeyMaxID < nID)
pwallet->nMasterKeyMaxID = nID;
vector<unsigned char> vchPrivKey;
ssValue >> vchPrivKey;
if (!pwallet->LoadCryptedKey(vchPubKey, vchPrivKey))
+ {
+ printf("Error reading wallet database: LoadCryptedKey failed\n");
return DB_CORRUPT;
+ }
fIsEncrypted = true;
}
else if (strType == "defaultkey")
if (nFileVersion == 10300)
nFileVersion = 300;
}
- else if (strType == "setting")
- {
- string strKey;
- ssKey >> strKey;
-
- // Options
-#ifndef QT_GUI
- if (strKey == "fGenerateBitcoins") ssValue >> fGenerateBitcoins;
-#endif
- if (strKey == "nTransactionFee") ssValue >> nTransactionFee;
- if (strKey == "fLimitProcessors") ssValue >> fLimitProcessors;
- if (strKey == "nLimitProcessors") ssValue >> nLimitProcessors;
- if (strKey == "fMinimizeToTray") ssValue >> fMinimizeToTray;
- if (strKey == "fMinimizeOnClose") ssValue >> fMinimizeOnClose;
- if (strKey == "fUseProxy") ssValue >> fUseProxy;
- if (strKey == "addrProxy") ssValue >> addrProxy;
- if (fHaveUPnP && strKey == "fUseUPnP") ssValue >> fUseUPnP;
- }
else if (strType == "minversion")
{
int nMinVersion = 0;
CScript script;
ssValue >> script;
if (!pwallet->LoadCScript(script))
+ {
+ printf("Error reading wallet database: LoadCScript failed\n");
return DB_CORRUPT;
+ }
}
}
pcursor->close();
WriteTx(hash, pwallet->mapWallet[hash]);
printf("nFileVersion = %d\n", nFileVersion);
- printf("fGenerateBitcoins = %d\n", fGenerateBitcoins);
- printf("nTransactionFee = %"PRI64d"\n", nTransactionFee);
- printf("fMinimizeToTray = %d\n", fMinimizeToTray);
- printf("fMinimizeOnClose = %d\n", fMinimizeOnClose);
- printf("fUseProxy = %d\n", fUseProxy);
- printf("addrProxy = %s\n", addrProxy.ToString().c_str());
- if (fHaveUPnP)
- printf("fUseUPnP = %d\n", fUseUPnP);
// Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc:
class CAccount;
class CAccountingEntry;
class CAddress;
+ class CAddrMan;
class CBlockLocator;
class CDiskBlockIndex;
class CDiskTxPos;
public:
bool WriteAddress(const CAddress& addr);
bool EraseAddress(const CAddress& addr);
- bool LoadAddresses();
+ bool WriteAddrman(const CAddrMan& addr);
+ bool LoadAddresses(bool &fUpdate);
};
bool LoadAddresses();
return Erase(std::make_pair(std::string("pool"), nPool));
}
+ // Settings are no longer stored in wallet.dat; these are
+ // used only for backwards compatibility:
template<typename T>
bool ReadSetting(const std::string& strKey, T& value)
{
return Read(std::make_pair(std::string("setting"), strKey), value);
}
-
template<typename T>
bool WriteSetting(const std::string& strKey, const T& value)
{
nWalletDBUpdated++;
return Write(std::make_pair(std::string("setting"), strKey), value);
}
+ bool EraseSetting(const std::string& strKey)
+ {
+ nWalletDBUpdated++;
+ return Erase(std::make_pair(std::string("setting"), strKey));
+ }
bool WriteMinVersion(int nVersion)
{
//
// Parameters
//
- // If Qt is used, parameters are parsed in qt/bitcoin.cpp's main()
+ // If Qt is used, parameters/bitcoin.conf are parsed in qt/bitcoin.cpp's main()
#if !defined(QT_GUI)
ParseParameters(argc, argv);
-#endif
-
- if (mapArgs.count("-datadir"))
+ if (!ReadConfigFile(mapArgs, mapMultiArgs))
{
- if (filesystem::is_directory(filesystem::system_complete(mapArgs["-datadir"])))
- {
- filesystem::path pathDataDir = filesystem::system_complete(mapArgs["-datadir"]);
- strlcpy(pszSetDataDir, pathDataDir.string().c_str(), sizeof(pszSetDataDir));
- }
- else
- {
- fprintf(stderr, "Error: Specified directory does not exist\n");
- Shutdown(NULL);
- }
+ fprintf(stderr, "Error: Specified directory does not exist\n");
+ Shutdown(NULL);
}
-
-
- ReadConfigFile(mapArgs, mapMultiArgs); // Must be done after processing datadir
+#endif
if (mapArgs.count("-?") || mapArgs.count("--help"))
{
" -gen \t\t " + _("Generate coins") + "\n" +
" -gen=0 \t\t " + _("Don't generate coins") + "\n" +
" -min \t\t " + _("Start minimized") + "\n" +
+ " -splash \t\t " + _("Show splash screen on startup (default: 1)") + "\n" +
" -datadir=<dir> \t\t " + _("Specify data directory") + "\n" +
+ " -dbcache=<n> \t\t " + _("Set database cache size in megabytes (default: 25)") + "\n" +
" -timeout=<n> \t " + _("Specify connection timeout (in milliseconds)") + "\n" +
" -proxy=<ip:port> \t " + _("Connect through socks4 proxy") + "\n" +
" -dns \t " + _("Allow DNS lookups for addnode and connect") + "\n" +
else if (nLoadWalletRet == DB_NEED_REWRITE)
{
strErrors << _("Wallet needed to be rewritten: restart Bitcoin to complete") << "\n";
+ printf("%s", strErrors.str().c_str());
wxMessageBox(strErrors.str(), "Bitcoin", wxOK | wxICON_ERROR);
return false;
}
else
strErrors << _("Error loading wallet.dat") << "\n";
}
+ printf("%s", strErrors.str().c_str());
printf(" wallet %15"PRI64d"ms\n", GetTimeMillis() - nStart);
RegisterWallet(pwalletMain);
return false;
}
- fGenerateBitcoins = GetBoolArg("-gen");
-
if (mapArgs.count("-proxy"))
{
fUseProxy = true;
fAllowDNS = GetBoolArg("-dns");
fNoListen = !GetBoolArg("-listen", true);
- // This code can be removed once a super-majority of the network has upgraded.
- if (GetBoolArg("-bip16", true))
- {
- if (fTestNet)
- SoftSetArg("-paytoscripthashtime", "1329264000"); // Feb 15
- else
- SoftSetArg("-paytoscripthashtime", "1330578000"); // Mar 1
-
- // Put "/P2SH/" in the coinbase so everybody can tell when
- // a majority of miners support it
- const char* pszP2SH = "/P2SH/";
- COINBASE_FLAGS << std::vector<unsigned char>(pszP2SH, pszP2SH+strlen(pszP2SH));
- }
- else
- {
- const char* pszP2SH = "NOP2SH";
- COINBASE_FLAGS << std::vector<unsigned char>(pszP2SH, pszP2SH+strlen(pszP2SH));
- }
-
- // Command-line args override in-wallet settings:
-#if USE_UPNP
- fUseUPnP = GetBoolArg("-upnp", true);
-#else
- fUseUPnP = GetBoolArg("-upnp", false);
-#endif
+ // Continue to put "/P2SH/" in the coinbase to monitor
+ // BIP16 support.
+ // This can be removed eventually...
+ const char* pszP2SH = "/P2SH/";
+ COINBASE_FLAGS << std::vector<unsigned char>(pszP2SH, pszP2SH+strlen(pszP2SH));
if (!fNoListen)
{
CAddress addr(CService(strAddr, GetDefaultPort(), fAllowDNS));
addr.nTime = 0; // so it won't relay unless successfully connected
if (addr.IsValid())
- AddAddress(addr);
+ addrman.Add(addr, CNetAddr("127.0.0.1"));
}
}
const string strMessageMagic = "Bitcoin Signed Message:\n";
-
double dHashesPerSec;
int64 nHPSTimerStart;
// Settings
-int fGenerateBitcoins = false;
int64 nTransactionFee = 0;
-int fLimitProcessors = false;
-int nLimitProcessors = 1;
-int fMinimizeToTray = true;
-int fMinimizeOnClose = true;
-#if USE_UPNP
-int fUseUPnP = true;
-#else
-int fUseUPnP = false;
-#endif
+
//////////////////////////////////////////////////////////////////////////////
// mapOrphanTransactions
//
-void static AddOrphanTx(const CDataStream& vMsg)
+void AddOrphanTx(const CDataStream& vMsg)
{
CTransaction tx;
CDataStream(vMsg) >> tx;
uint256 hash = tx.GetHash();
if (mapOrphanTransactions.count(hash))
return;
+
CDataStream* pvMsg = mapOrphanTransactions[hash] = new CDataStream(vMsg);
BOOST_FOREACH(const CTxIn& txin, tx.vin)
mapOrphanTransactionsByPrev.insert(make_pair(txin.prevout.hash, pvMsg));
mapOrphanTransactions.erase(hash);
}
+int LimitOrphanTxSize(int nMaxOrphans)
+{
+ int nEvicted = 0;
+ while (mapOrphanTransactions.size() > nMaxOrphans)
+ {
+ // Evict a random orphan:
+ std::vector<unsigned char> randbytes(32);
+ RAND_bytes(&randbytes[0], 32);
+ uint256 randomhash(randbytes);
+ map<uint256, CDataStream*>::iterator it = mapOrphanTransactions.lower_bound(randomhash);
+ if (it == mapOrphanTransactions.end())
+ it = mapOrphanTransactions.begin();
+ EraseOrphanTx(it->first);
+ ++nEvicted;
+ }
+ return nEvicted;
+}
}
// Remove transaction from index
- if (!txdb.EraseTxIndex(*this))
- return error("DisconnectInputs() : EraseTxPos failed");
+ // This can fail if a duplicate of this transaction was in a chain that got
+ // reorganized away. This is only possible if this transaction was completely
+ // spent, so erasing it would be a no-op anway.
+ txdb.EraseTxIndex(*this);
return true;
}
{
// Verify signature
if (!VerifySignature(txPrev, *this, i, fStrictPayToScriptHash, 0))
+ {
+ // only during transition phase for P2SH: do not invoke anti-DoS code for
+ // potentially old clients relaying bad P2SH transactions
+ if (fStrictPayToScriptHash && VerifySignature(txPrev, *this, i, false, 0))
+ return error("ConnectInputs() : %s P2SH VerifySignature failed", GetHash().ToString().substr(0,10).c_str());
+
return DoS(100,error("ConnectInputs() : %s VerifySignature failed", GetHash().ToString().substr(0,10).c_str()));
+ }
}
// Mark outpoints as spent
if (!CheckBlock())
return false;
- // To avoid being on the short end of a block-chain split,
- // don't do secondary validation of pay-to-script-hash transactions
- // until blocks with timestamps after paytoscripthashtime (see init.cpp for default).
- // This code can be removed once a super-majority of the network has upgraded.
- int64 nEvalSwitchTime = GetArg("-paytoscripthashtime", std::numeric_limits<int64_t>::max());
- bool fStrictPayToScriptHash = (pindex->nTime >= nEvalSwitchTime);
+ // Do not allow blocks that contain transactions which 'overwrite' older transactions,
+ // unless those are already completely spent.
+ // If such overwrites are allowed, coinbases and transactions depending upon those
+ // can be duplicated to remove the ability to spend the first instance -- even after
+ // being sent to another address.
+ // See BIP30 and http://r6.ca/blog/20120206T005236Z.html for more information.
+ // This logic is not necessary for memory pool transactions, as AcceptToMemoryPool
+ // already refuses previously-known transaction id's entirely.
+ // This rule applies to all blocks whose timestamp is after March 15, 2012, 0:00 UTC.
+ // On testnet it is enabled as of februari 20, 2012, 0:00 UTC.
+ if (pindex->nTime > 1331769600 || (fTestNet && pindex->nTime > 1329696000))
+ BOOST_FOREACH(CTransaction& tx, vtx)
+ {
+ CTxIndex txindexOld;
+ if (txdb.ReadTxIndex(tx.GetHash(), txindexOld))
+ BOOST_FOREACH(CDiskTxPos &pos, txindexOld.vSpent)
+ if (pos.IsNull())
+ return false;
+ }
+
+ // BIP16 didn't become active until Apr 1 2012 (Feb 15 on testnet)
+ int64 nBIP16SwitchTime = fTestNet ? 1329264000 : 1333238400;
+ bool fStrictPayToScriptHash = (pindex->nTime >= nBIP16SwitchTime);
//// issue here: it doesn't know the version
unsigned int nTxPos = pindex->nBlockPos + ::GetSerializeSize(CBlock(), SER_DISK) - 1 + GetSizeOfCompactSize(vtx.size());
vConnect.push_back(pindex);
reverse(vConnect.begin(), vConnect.end());
+ printf("REORGANIZE: Disconnect %i blocks; %s..%s\n", vDisconnect.size(), pfork->GetBlockHash().ToString().substr(0,20).c_str(), pindexBest->GetBlockHash().ToString().substr(0,20).c_str());
+ printf("REORGANIZE: Connect %i blocks; %s..%s\n", vConnect.size(), pfork->GetBlockHash().ToString().substr(0,20).c_str(), pindexNew->GetBlockHash().ToString().substr(0,20).c_str());
+
// Disconnect shorter branch
vector<CTransaction> vResurrect;
BOOST_FOREACH(CBlockIndex* pindex, vDisconnect)
if (!block.ReadFromDisk(pindex))
return error("Reorganize() : ReadFromDisk for disconnect failed");
if (!block.DisconnectBlock(txdb, pindex))
- return error("Reorganize() : DisconnectBlock failed");
+ return error("Reorganize() : DisconnectBlock %s failed", pindex->GetBlockHash().ToString().substr(0,20).c_str());
// Queue memory transactions to resurrect
BOOST_FOREACH(const CTransaction& tx, block.vtx)
{
// Invalid block
txdb.TxnAbort();
- return error("Reorganize() : ConnectBlock failed");
+ return error("Reorganize() : ConnectBlock %s failed", pindex->GetBlockHash().ToString().substr(0,20).c_str());
}
// Queue memory transactions to delete
BOOST_FOREACH(CTransaction& tx, vDelete)
tx.RemoveFromMemoryPool();
- printf("REORGANIZE: Disconnected %i blocks; %s..%s\n", vDisconnect.size(), pfork->GetBlockHash().ToString().substr(0,20).c_str(), pindexBest->GetBlockHash().ToString().substr(0,20).c_str());
- printf("REORGANIZE: Connected %i blocks; %s..%s\n", vConnect.size(), pfork->GetBlockHash().ToString().substr(0,20).c_str(), pindexNew->GetBlockHash().ToString().substr(0,20).c_str());
+ printf("REORGANIZE: done\n");
return true;
}
printf("runCommand error: system(%s) returned %d\n", strCommand.c_str(), nErr);
}
+// Called from inside SetBestChain: attaches a block to the new best chain being built
+bool CBlock::SetBestChainInner(CTxDB& txdb, CBlockIndex *pindexNew)
+{
+ uint256 hash = GetHash();
+
+ // Adding to current best branch
+ if (!ConnectBlock(txdb, pindexNew) || !txdb.WriteHashBestChain(hash))
+ {
+ txdb.TxnAbort();
+ InvalidChainFound(pindexNew);
+ return false;
+ }
+ if (!txdb.TxnCommit())
+ return error("SetBestChain() : TxnCommit failed");
+
+ // Add to current best branch
+ pindexNew->pprev->pnext = pindexNew;
+
+ // Delete redundant memory transactions
+ BOOST_FOREACH(CTransaction& tx, vtx)
+ tx.RemoveFromMemoryPool();
+
+ return true;
+}
+
bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew)
{
uint256 hash = GetHash();
}
else if (hashPrevBlock == hashBestChain)
{
- // Adding to current best branch
- if (!ConnectBlock(txdb, pindexNew) || !txdb.WriteHashBestChain(hash))
+ if (!SetBestChainInner(txdb, pindexNew))
+ return error("SetBestChain() : SetBestChainInner failed");
+ }
+ else
+ {
+ // the first block in the new chain that will cause it to become the new best chain
+ CBlockIndex *pindexIntermediate = pindexNew;
+
+ // list of blocks that need to be connected afterwards
+ std::vector<CBlockIndex*> vpindexSecondary;
+
+ // Reorganize is costly in terms of db load, as it works in a single db transaction.
+ // Try to limit how much needs to be done inside
+ while (pindexIntermediate->pprev && pindexIntermediate->pprev->bnChainWork > pindexBest->bnChainWork)
{
- txdb.TxnAbort();
- InvalidChainFound(pindexNew);
- return error("SetBestChain() : ConnectBlock failed");
+ vpindexSecondary.push_back(pindexIntermediate);
+ pindexIntermediate = pindexIntermediate->pprev;
}
- if (!txdb.TxnCommit())
- return error("SetBestChain() : TxnCommit failed");
- // Add to current best branch
- pindexNew->pprev->pnext = pindexNew;
+ if (!vpindexSecondary.empty())
+ printf("Postponing %i reconnects\n", vpindexSecondary.size());
- // Delete redundant memory transactions
- BOOST_FOREACH(CTransaction& tx, vtx)
- tx.RemoveFromMemoryPool();
- }
- else
- {
- // New best branch
- if (!Reorganize(txdb, pindexNew))
+ // Switch to new best branch
+ if (!Reorganize(txdb, pindexIntermediate))
{
txdb.TxnAbort();
InvalidChainFound(pindexNew);
return error("SetBestChain() : Reorganize failed");
}
+
+ // Connect futher blocks
+ BOOST_REVERSE_FOREACH(CBlockIndex *pindex, vpindexSecondary)
+ {
+ CBlock block;
+ if (!block.ReadFromDisk(pindex))
+ {
+ printf("SetBestChain() : ReadFromDisk failed\n");
+ break;
+ }
+ txdb.TxnBegin();
+ // errors now are not fatal, we still did a reorganisation to a new chain in a valid way
+ if (!block.SetBestChainInner(txdb, pindex))
+ break;
+ }
}
// Update best block in wallet (so we can detect restored wallets)
return error("AcceptBlock() : AddToBlockIndex failed");
// Relay inventory, but don't relay old inventory during initial block download
+ int nBlockEstimate = Checkpoints::GetTotalBlocksEstimate();
if (hashBestChain == hash)
CRITICAL_BLOCK(cs_vNodes)
BOOST_FOREACH(CNode* pnode, vNodes)
- if (nBestHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : 140700))
+ if (nBestHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate))
pnode->PushInventory(CInv(MSG_BLOCK, hash));
return true;
vRecv >> pfrom->nVersion >> pfrom->nServices >> nTime >> addrMe;
if (pfrom->nVersion < 209)
{
- // Since Februari 20, 2012, the protocol is initiated at version 209,
+ // Since February 20, 2012, the protocol is initiated at version 209,
// and earlier versions are no longer supported
printf("partner %s using obsolete version %i; disconnecting\n", pfrom->addr.ToString().c_str(), pfrom->nVersion);
pfrom->fDisconnect = true;
}
// Get recent addresses
- if (pfrom->nVersion >= 31402 || mapAddresses.size() < 1000)
+ if (pfrom->nVersion >= 31402 || addrman.size() < 1000)
{
pfrom->PushMessage("getaddr");
pfrom->fGetAddr = true;
}
+ addrman.Good(pfrom->addr);
+ } else {
+ if (((CNetAddr)pfrom->addr) == (CNetAddr)addrFrom)
+ {
+ addrman.Add(addrFrom, addrFrom);
+ addrman.Good(addrFrom);
+ }
}
// Ask the first connected node for block updates
vRecv >> vAddr;
// Don't want addr from older versions unless seeding
- if (pfrom->nVersion < 31402 && mapAddresses.size() > 1000)
+ if (pfrom->nVersion < 31402 && addrman.size() > 1000)
return true;
if (vAddr.size() > 1000)
{
}
// Store the new addresses
- CAddrDB addrDB;
- addrDB.TxnBegin();
int64 nNow = GetAdjustedTime();
int64 nSince = nNow - 10 * 60;
BOOST_FOREACH(CAddress& addr, vAddr)
continue;
if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60)
addr.nTime = nNow - 5 * 24 * 60 * 60;
- AddAddress(addr, 2 * 60 * 60, &addrDB);
pfrom->AddAddressKnown(addr);
if (addr.nTime > nSince && !pfrom->fGetAddr && vAddr.size() <= 10 && addr.IsRoutable())
{
}
}
}
- addrDB.TxnCommit(); // Save addresses (it's ok if this fails)
+ addrman.Add(vAddr, pfrom->addr, 2 * 60 * 60);
if (vAddr.size() < 1000)
pfrom->fGetAddr = false;
}
}
CTxDB txdb("r");
- BOOST_FOREACH(const CInv& inv, vInv)
+ for (int nInv = 0; nInv < vInv.size(); nInv++)
{
+ const CInv &inv = vInv[nInv];
+
if (fShutdown)
return true;
pfrom->AddInventoryKnown(inv);
if (fDebug)
printf(" got inventory: %s %s\n", inv.ToString().c_str(), fAlreadyHave ? "have" : "new");
- if (!fAlreadyHave)
+ // Always request the last block in an inv bundle (even if we already have it), as it is the
+ // trigger for the other side to send further invs. If we are stuck on a (very long) side chain,
+ // this is necessary to connect earlier received orphan blocks to the chain again.
+ if (!fAlreadyHave || (inv.type == MSG_BLOCK && nInv==vInv.size()-1))
pfrom->AskFor(inv);
- else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash))
+ if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash))
pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(mapOrphanBlocks[inv.hash]));
// Track requests for our stuff
{
printf("storing orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str());
AddOrphanTx(vMsg);
+
+ // DoS prevention: do not allow mapOrphanTransactions to grow unbounded
+ int nEvicted = LimitOrphanTxSize(MAX_ORPHAN_TRANSACTIONS);
+ if (nEvicted > 0)
+ printf("mapOrphan overflow, removed %d tx\n", nEvicted);
}
if (tx.nDoS) pfrom->Misbehaving(tx.nDoS);
}
else if (strCommand == "getaddr")
{
- // Nodes rebroadcast an addr every 24 hours
pfrom->vAddrToSend.clear();
- int64 nSince = GetAdjustedTime() - 3 * 60 * 60; // in the last 3 hours
- CRITICAL_BLOCK(cs_mapAddresses)
- {
- unsigned int nCount = 0;
- BOOST_FOREACH(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses)
- {
- const CAddress& addr = item.second;
- if (addr.nTime > nSince)
- nCount++;
- }
- BOOST_FOREACH(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses)
- {
- const CAddress& addr = item.second;
- if (addr.nTime > nSince && GetRand(nCount) < 2500)
- pfrom->PushAddress(addr);
- }
- }
+ vector<CAddress> vAddr = addrman.GetAddr();
+ BOOST_FOREACH(const CAddress &addr, vAddr)
+ pfrom->PushAddress(addr);
}
nLastRebroadcast = GetTime();
}
- // Clear out old addresses periodically so it's not too much work at once
- static int64 nLastClear;
- if (nLastClear == 0)
- nLastClear = GetTime();
- if (GetTime() - nLastClear > 10 * 60 && vNodes.size() >= 3)
- {
- nLastClear = GetTime();
- CRITICAL_BLOCK(cs_mapAddresses)
- {
- CAddrDB addrdb;
- int64 nSince = GetAdjustedTime() - 14 * 24 * 60 * 60;
- for (map<vector<unsigned char>, CAddress>::iterator mi = mapAddresses.begin();
- mi != mapAddresses.end();)
- {
- const CAddress& addr = (*mi).second;
- if (addr.nTime < nSince)
- {
- if (mapAddresses.size() < 1000 || GetTime() > nLastClear + 20)
- break;
- addrdb.EraseAddress(addr);
- mapAddresses.erase(mi++);
- }
- else
- mi++;
- }
- }
- }
-
-
//
// Message: addr
//
void static ThreadBitcoinMiner(void* parg);
+static bool fGenerateBitcoins = false;
+static bool fLimitProcessors = false;
+static int nLimitProcessors = -1;
+
void static BitcoinMiner(CWallet *pwallet)
{
printf("BitcoinMiner started\n");
void GenerateBitcoins(bool fGenerate, CWallet* pwallet)
{
- if (fGenerateBitcoins != fGenerate)
- {
- fGenerateBitcoins = fGenerate;
- WriteSetting("fGenerateBitcoins", fGenerateBitcoins);
- MainFrameRepaint();
- }
- if (fGenerateBitcoins)
+ fGenerateBitcoins = fGenerate;
+ nLimitProcessors = GetArg("-genproclimit", -1);
+ if (nLimitProcessors == 0)
+ fGenerateBitcoins = false;
+ fLimitProcessors = (nLimitProcessors != -1);
+
+ if (fGenerate)
{
int nProcessors = boost::thread::hardware_concurrency();
printf("%d processors\n", nProcessors);
DEBUGFLAGS=-g
CXXFLAGS=-O2
-xCXXFLAGS=-pthread -Wextra -Wno-sign-compare -Wno-char-subscripts -Wno-invalid-offsetof -Wformat-security \
+xCXXFLAGS=-pthread -Wextra -Wno-sign-compare -Wno-char-subscripts -Wno-invalid-offsetof -Wformat -Wformat-security \
$(DEBUGFLAGS) $(DEFS) $(HARDENING) $(CXXFLAGS)
OBJS= \
obj/checkpoints.o \
obj/netbase.o \
+ obj/addrman.o \
obj/crypter.o \
obj/key.o \
obj/db.o \
#include "net.h"
#include "init.h"
#include "strlcpy.h"
+ #include "addrman.h"
#ifdef WIN32
#include <string.h>
//
bool fClient = false;
bool fAllowDNS = false;
+static bool fUseUPnP = false;
uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK);
CAddress addrLocalHost(CService("0.0.0.0", 0), nLocalServices);
static CNode* pnodeLocalHost = NULL;
uint64 nLocalHostNonce = 0;
array<int, THREAD_MAX> vnThreadsRunning;
static SOCKET hListenSocket = INVALID_SOCKET;
+ CAddrMan addrman;
vector<CNode*> vNodes;
CCriticalSection cs_vNodes;
- map<vector<unsigned char>, CAddress> mapAddresses;
- CCriticalSection cs_mapAddresses;
map<CInv, CDataStream> mapRelay;
deque<pair<int64, CInv> > vRelayExpiration;
CCriticalSection cs_mapRelay;
- bool AddAddress(CAddress addr, int64 nTimePenalty, CAddrDB *pAddrDB)
- {
- if (!addr.IsRoutable())
- return false;
- if ((CService)addr == (CService)addrLocalHost)
- return false;
- addr.nTime = max((int64)0, (int64)addr.nTime - nTimePenalty);
- bool fUpdated = false;
- bool fNew = false;
- CAddress addrFound = addr;
-
- CRITICAL_BLOCK(cs_mapAddresses)
- {
- map<vector<unsigned char>, CAddress>::iterator it = mapAddresses.find(addr.GetKey());
- if (it == mapAddresses.end())
- {
- // New address
- printf("AddAddress(%s)\n", addr.ToString().c_str());
- mapAddresses.insert(make_pair(addr.GetKey(), addr));
- fUpdated = true;
- fNew = true;
- }
- else
- {
- addrFound = (*it).second;
- if ((addrFound.nServices | addr.nServices) != addrFound.nServices)
- {
- // Services have been added
- addrFound.nServices |= addr.nServices;
- fUpdated = true;
- }
- bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60);
- int64 nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60);
- if (addrFound.nTime < addr.nTime - nUpdateInterval)
- {
- // Periodically update most recently seen time
- addrFound.nTime = addr.nTime;
- fUpdated = true;
- }
- }
- }
- // There is a nasty deadlock bug if this is done inside the cs_mapAddresses
- // CRITICAL_BLOCK:
- // Thread 1: begin db transaction (locks inside-db-mutex)
- // then AddAddress (locks cs_mapAddresses)
- // Thread 2: AddAddress (locks cs_mapAddresses)
- // ... then db operation hangs waiting for inside-db-mutex
- if (fUpdated)
- {
- if (pAddrDB)
- pAddrDB->WriteAddress(addrFound);
- else
- CAddrDB().WriteAddress(addrFound);
- }
- return fNew;
- }
-
void AddressCurrentlyConnected(const CService& addr)
{
- CAddress *paddrFound = NULL;
-
- CRITICAL_BLOCK(cs_mapAddresses)
- {
- // Only if it's been published already
- map<vector<unsigned char>, CAddress>::iterator it = mapAddresses.find(addr.GetKey());
- if (it != mapAddresses.end())
- paddrFound = &(*it).second;
- }
-
- if (paddrFound)
- {
- int64 nUpdateInterval = 20 * 60;
- if (paddrFound->nTime < GetAdjustedTime() - nUpdateInterval)
- {
- // Periodically update most recently seen time
- paddrFound->nTime = GetAdjustedTime();
- CAddrDB addrdb;
- addrdb.WriteAddress(*paddrFound);
- }
- }
+ addrman.Connected(addr);
}
}
/// debug print
- printf("trying connection %s lastseen=%.1fhrs lasttry=%.1fhrs\n",
+ printf("trying connection %s lastseen=%.1fhrs\n",
addrConnect.ToString().c_str(),
- (double)(addrConnect.nTime - GetAdjustedTime())/3600.0,
- (double)(addrConnect.nLastTry - GetAdjustedTime())/3600.0);
+ (double)(addrConnect.nTime - GetAdjustedTime())/3600.0);
- CRITICAL_BLOCK(cs_mapAddresses)
- mapAddresses[addrConnect.GetKey()].nLastTry = GetAdjustedTime();
+ addrman.Attempt(addrConnect);
// Connect
SOCKET hSocket;
printf("disconnecting node %s\n", addr.ToString().c_str());
closesocket(hSocket);
hSocket = INVALID_SOCKET;
+ vRecv.clear();
}
}
}
else if (CNode::IsBanned(addr))
{
- printf("connetion from %s dropped (banned)\n", addr.ToString().c_str());
+ printf("connection from %s dropped (banned)\n", addr.ToString().c_str());
closesocket(hSocket);
}
else
if (fUseUPnP != fMapPort)
{
fUseUPnP = fMapPort;
- WriteSetting("fUseUPnP", fUseUPnP);
}
if (fUseUPnP && vnThreadsRunning[THREAD_UPNP] < 1)
{
-
- static const char *strDNSSeed[] = {
- "bitseed.xf2.org",
- "dnsseed.bluematt.me",
- "seed.bitcoin.sipa.be",
- "dnsseed.bitcoin.dashjr.org",
+ // DNS seeds
+ // Each pair gives a source name and a seed name.
+ // The first name is used as information source for addrman.
+ // The second name should resolve to a list of seed addresses.
+ static const char *strDNSSeed[][2] = {
+ {"xf2.org", "bitseed.xf2.org"},
+ {"bluematt.me", "dnsseed.bluematt.me"},
+ {"bitcoin.sipa.be", "seed.bitcoin.sipa.be"},
+ {"dashjr.org", "dnsseed.bitcoin.dashjr.org"},
};
void ThreadDNSAddressSeed(void* parg)
for (int seed_idx = 0; seed_idx < ARRAYLEN(strDNSSeed); seed_idx++) {
vector<CNetAddr> vaddr;
- if (LookupHost(strDNSSeed[seed_idx], vaddr))
+ vector<CAddress> vAdd;
+ if (LookupHost(strDNSSeed[seed_idx][1], vaddr))
{
- CAddrDB addrDB;
- addrDB.TxnBegin();
- BOOST_FOREACH (CNetAddr& ip, vaddr)
+ BOOST_FOREACH(CNetAddr& ip, vaddr)
{
- if (ip.IsRoutable())
- {
- CAddress addr(CService(ip, GetDefaultPort()), NODE_NETWORK);
- addr.nTime = 0;
- AddAddress(addr, 0, &addrDB);
- found++;
- }
+ CAddress addr = CAddress(CService(ip, GetDefaultPort()));
+ addr.nTime = 0;
+ vAdd.push_back(addr);
+ found++;
}
- addrDB.TxnCommit(); // Save addresses (it's ok if this fails)
}
+ addrman.Add(vAdd, CNetAddr(strDNSSeed[seed_idx][0], true));
}
}
0xc461d84a, 0xb2dbe247,
};
+ void DumpAddresses()
+ {
+ CAddrDB adb;
+ adb.WriteAddrman(addrman);
+ }
+ void ThreadDumpAddress2(void* parg)
+ {
+ vnThreadsRunning[THREAD_DUMPADDRESS]++;
+ while (!fShutdown)
+ {
+ DumpAddresses();
+ vnThreadsRunning[THREAD_DUMPADDRESS]--;
+ Sleep(100000);
+ vnThreadsRunning[THREAD_DUMPADDRESS]++;
+ }
+ vnThreadsRunning[THREAD_DUMPADDRESS]--;
+ }
+
+ void ThreadDumpAddress(void* parg)
+ {
+ IMPLEMENT_RANDOMIZE_STACK(ThreadDumpAddress(parg));
+ try
+ {
+ ThreadDumpAddress2(parg);
+ }
+ catch (std::exception& e) {
+ PrintException(&e, "ThreadDumpAddress()");
+ }
+ printf("ThreadDumpAddress exiting\n");
+ }
void ThreadOpenConnections(void* parg)
{
int64 nStart = GetTime();
loop
{
+ int nOutbound = 0;
+
vnThreadsRunning[THREAD_OPENCONNECTIONS]--;
Sleep(500);
vnThreadsRunning[THREAD_OPENCONNECTIONS]++;
// Limit outbound connections
loop
{
- int nOutbound = 0;
+ nOutbound = 0;
CRITICAL_BLOCK(cs_vNodes)
BOOST_FOREACH(CNode* pnode, vNodes)
if (!pnode->fInbound)
bool fAddSeeds = false;
- CRITICAL_BLOCK(cs_mapAddresses)
- {
- // Add seed nodes if IRC isn't working
- bool fTOR = (fUseProxy && addrProxy.GetPort() == 9050);
- if (mapAddresses.empty() && (GetTime() - nStart > 60 || fTOR) && !fTestNet)
- fAddSeeds = true;
- }
-
- if (fAddSeeds)
+ // Add seed nodes if IRC isn't working
+ bool fTOR = (fUseProxy && addrProxy.GetPort() == 9050);
+ if (addrman.size()==0 && (GetTime() - nStart > 60 || fTOR) && !fTestNet)
{
+ std::vector<CAddress> vAdd;
for (int i = 0; i < ARRAYLEN(pnSeed); i++)
{
// It'll only connect to one or two seed nodes because once it connects,
memcpy(&ip, &pnSeed[i], sizeof(ip));
CAddress addr(CService(ip, GetDefaultPort()));
addr.nTime = GetTime()-GetRand(nOneWeek)-nOneWeek;
- AddAddress(addr);
+ vAdd.push_back(addr);
}
+ addrman.Add(vAdd, CNetAddr("127.0.0.1"));
}
//
int64 nANow = GetAdjustedTime();
- CRITICAL_BLOCK(cs_mapAddresses)
+ int nTries = 0;
+ loop
{
- BOOST_FOREACH(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses)
- {
- const CAddress& addr = item.second;
- if (!addr.IsIPv4() || !addr.IsValid() || setConnected.count(addr.GetGroup()))
- continue;
- int64 nSinceLastSeen = nANow - addr.nTime;
- int64 nSinceLastTry = nANow - addr.nLastTry;
-
- // Randomize the order in a deterministic way, putting the standard port first
- int64 nRandomizer = (uint64)(nStart * 4951 + addr.nLastTry * 9567851 + addr.GetHash()) % (2 * 60 * 60);
- if (addr.GetPort() != GetDefaultPort())
- nRandomizer += 2 * 60 * 60;
-
- // Last seen Base retry frequency
- // <1 hour 10 min
- // 1 hour 1 hour
- // 4 hours 2 hours
- // 24 hours 5 hours
- // 48 hours 7 hours
- // 7 days 13 hours
- // 30 days 27 hours
- // 90 days 46 hours
- // 365 days 93 hours
- int64 nDelay = (int64)(3600.0 * sqrt(fabs((double)nSinceLastSeen) / 3600.0) + nRandomizer);
-
- // Fast reconnect for one hour after last seen
- if (nSinceLastSeen < 60 * 60)
- nDelay = 10 * 60;
-
- // Limit retry frequency
- if (nSinceLastTry < nDelay)
- continue;
+ // use an nUnkBias between 10 (no outgoing connections) and 90 (8 outgoing connections)
+ CAddress addr = addrman.Select(10 + min(nOutbound,8)*10);
- // If we have IRC, we'll be notified when they first come online,
- // and again every 24 hours by the refresh broadcast.
- if (nGotIRCAddresses > 0 && vNodes.size() >= 2 && nSinceLastSeen > 24 * 60 * 60)
- continue;
+ // if we selected an invalid address, restart
+ if (!addr.IsIPv4() || !addr.IsValid() || setConnected.count(addr.GetGroup()) || addr == addrLocalHost)
+ break;
- // Only try the old stuff if we don't have enough connections
- if (vNodes.size() >= 8 && nSinceLastSeen > 24 * 60 * 60)
- continue;
+ nTries++;
- // If multiple addresses are ready, prioritize by time since
- // last seen and time since last tried.
- int64 nScore = min(nSinceLastTry, (int64)24 * 60 * 60) - nSinceLastSeen - nRandomizer;
- if (nScore > nBest)
- {
- nBest = nScore;
- addrConnect = addr;
- }
- }
+ // only consider very recently tried nodes after 30 failed attempts
+ if (nANow - addr.nLastTry < 600 && nTries < 30)
+ continue;
+
+ // do not allow non-default ports, unless after 50 invalid addresses selected already
+ if (addr.GetPort() != GetDefaultPort() && nTries < 50)
+ continue;
+
+ addrConnect = addr;
+ break;
}
if (addrConnect.IsValid())
void StartNode(void* parg)
{
+#ifdef USE_UPNP
+#if USE_UPNP
+ fUseUPnP = GetBoolArg("-upnp", true);
+#else
+ fUseUPnP = GetBoolArg("-upnp", false);
+#endif
+#endif
+
if (pnodeLocalHost == NULL)
pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress(CService("127.0.0.1", 0), nLocalServices));
if (!CreateThread(ThreadMessageHandler, NULL))
printf("Error: CreateThread(ThreadMessageHandler) failed\n");
+ // Dump network addresses
+ if (!CreateThread(ThreadDumpAddress, NULL))
+ printf("Error; CreateThread(ThreadDumpAddress) failed\n");
+
// Generate coins in the background
- GenerateBitcoins(fGenerateBitcoins, pwalletMain);
+ GenerateBitcoins(GetBoolArg("-gen", false), pwalletMain);
}
bool StopNode()
if (fHaveUPnP && vnThreadsRunning[THREAD_UPNP] > 0) printf("ThreadMapPort still running\n");
if (vnThreadsRunning[THREAD_DNSSEED] > 0) printf("ThreadDNSAddressSeed still running\n");
if (vnThreadsRunning[THREAD_ADDEDCONNECTIONS] > 0) printf("ThreadOpenAddedConnections still running\n");
+ if (vnThreadsRunning[THREAD_DUMPADDRESS] > 0) printf("ThreadDumpAddresses still running\n");
while (vnThreadsRunning[THREAD_MESSAGEHANDLER] > 0 || vnThreadsRunning[THREAD_RPCSERVER] > 0)
Sleep(20);
Sleep(50);
-
+ DumpAddresses();
return true;
}
#include <arpa/inet.h>
#endif
+#include "mruset.h"
#include "netbase.h"
#include "protocol.h"
+ #include "addrman.h"
class CAddrDB;
class CRequestTracker;
bool RecvLine(SOCKET hSocket, std::string& strLine);
bool GetMyExternalIP(CNetAddr& ipRet);
- bool AddAddress(CAddress addr, int64 nTimePenalty=0, CAddrDB *pAddrDB=NULL);
void AddressCurrentlyConnected(const CService& addr);
CNode* FindNode(const CNetAddr& ip);
CNode* FindNode(const CService& ip);
THREAD_UPNP,
THREAD_DNSSEED,
THREAD_ADDEDCONNECTIONS,
+ THREAD_DUMPADDRESS,
THREAD_MAX
};
extern CAddress addrLocalHost;
extern uint64 nLocalHostNonce;
extern boost::array<int, THREAD_MAX> vnThreadsRunning;
+ extern CAddrMan addrman;
extern std::vector<CNode*> vNodes;
extern CCriticalSection cs_vNodes;
- extern std::map<std::vector<unsigned char>, CAddress> mapAddresses;
- extern CCriticalSection cs_mapAddresses;
extern std::map<CInv, CDataStream> mapRelay;
extern std::deque<std::pair<int64, CInv> > vRelayExpiration;
extern CCriticalSection cs_mapRelay;
std::set<uint256> setKnown;
// inventory based relay
- std::set<CInv> setInventoryKnown;
+ mruset<CInv> setInventoryKnown;
std::vector<CInv> vInventoryToSend;
CCriticalSection cs_inventory;
std::multimap<int64, CInv> mapAskFor;
fGetAddr = false;
vfSubscribe.assign(256, false);
nMisbehavior = 0;
+ setInventoryKnown.max_size(SendBufferSize() / 1000);
// Be shy and don't send version until we hear
if (!fInbound)