aboutsummaryrefslogtreecommitdiff
path: root/src/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.cpp')
-rw-r--r--src/main.cpp116
1 files changed, 72 insertions, 44 deletions
diff --git a/src/main.cpp b/src/main.cpp
index 1c040bdee7..78d84d9064 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -2,11 +2,11 @@
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
-#include "headers.h"
#include "checkpoints.h"
#include "db.h"
#include "net.h"
#include "init.h"
+#include "ui_interface.h"
#include <boost/algorithm/string/replace.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
@@ -286,7 +286,7 @@ bool CTransaction::AreInputsStandard(const MapPrevTx& mapInputs) const
if (IsCoinBase())
return true; // Coinbases don't use vin normally
- for (int i = 0; i < vin.size(); i++)
+ for (unsigned int i = 0; i < vin.size(); i++)
{
const CTxOut& prev = GetOutputFor(vin[i], mapInputs);
@@ -409,7 +409,7 @@ bool CTransaction::CheckTransaction() const
if (vout.empty())
return DoS(10, error("CTransaction::CheckTransaction() : vout empty"));
// Size limits
- if (::GetSerializeSize(*this, SER_NETWORK) > MAX_BLOCK_SIZE)
+ if (::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE)
return DoS(100, error("CTransaction::CheckTransaction() : size limits failed"));
// Check for negative or overflow output values
@@ -483,7 +483,7 @@ bool CTxMemPool::accept(CTxDB& txdb, CTransaction &tx, bool fCheckInputs,
// Check for conflicts with in-memory transactions
CTransaction* ptxOld = NULL;
- for (int i = 0; i < tx.vin.size(); i++)
+ for (unsigned int i = 0; i < tx.vin.size(); i++)
{
COutPoint outpoint = tx.vin[i].prevout;
if (mapNextTx.count(outpoint))
@@ -499,7 +499,7 @@ bool CTxMemPool::accept(CTxDB& txdb, CTransaction &tx, bool fCheckInputs,
return false;
if (!tx.IsNewerThan(*ptxOld))
return false;
- for (int i = 0; i < tx.vin.size(); i++)
+ for (unsigned int i = 0; i < tx.vin.size(); i++)
{
COutPoint outpoint = tx.vin[i].prevout;
if (!mapNextTx.count(outpoint) || mapNextTx[outpoint].ptx != ptxOld)
@@ -532,7 +532,7 @@ bool CTxMemPool::accept(CTxDB& txdb, CTransaction &tx, bool fCheckInputs,
// reasonable number of ECDSA signature verifications.
int64 nFees = tx.GetValueIn(mapInputs)-tx.GetValueOut();
- unsigned int nSize = ::GetSerializeSize(tx, SER_NETWORK);
+ unsigned int nSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
// Don't accept it if it can't get into a block
if (nFees < tx.GetMinFee(1000, true, GMF_RELAY))
@@ -605,7 +605,7 @@ bool CTxMemPool::addUnchecked(CTransaction &tx)
LOCK(cs);
uint256 hash = tx.GetHash();
mapTx[hash] = tx;
- for (int i = 0; i < tx.vin.size(); i++)
+ for (unsigned int i = 0; i < tx.vin.size(); i++)
mapNextTx[tx.vin[i].prevout] = CInPoint(&mapTx[hash], i);
nTransactionsUpdated++;
}
@@ -989,7 +989,7 @@ bool CTransaction::FetchInputs(CTxDB& txdb, const map<uint256, CTxIndex>& mapTes
if (IsCoinBase())
return true; // Coinbase transactions have no inputs to fetch.
- for (int i = 0; i < vin.size(); i++)
+ for (unsigned int i = 0; i < vin.size(); i++)
{
COutPoint prevout = vin[i].prevout;
if (inputsRet.count(prevout.hash))
@@ -1034,7 +1034,7 @@ bool CTransaction::FetchInputs(CTxDB& txdb, const map<uint256, CTxIndex>& mapTes
}
// Make sure all prevout.n's are valid:
- for (int i = 0; i < vin.size(); i++)
+ for (unsigned int i = 0; i < vin.size(); i++)
{
const COutPoint prevout = vin[i].prevout;
assert(inputsRet.count(prevout.hash) != 0);
@@ -1071,7 +1071,7 @@ int64 CTransaction::GetValueIn(const MapPrevTx& inputs) const
return 0;
int64 nResult = 0;
- for (int i = 0; i < vin.size(); i++)
+ for (unsigned int i = 0; i < vin.size(); i++)
{
nResult += GetOutputFor(vin[i], inputs).nValue;
}
@@ -1085,7 +1085,7 @@ int CTransaction::GetP2SHSigOpCount(const MapPrevTx& inputs) const
return 0;
int nSigOps = 0;
- for (int i = 0; i < vin.size(); i++)
+ for (unsigned int i = 0; i < vin.size(); i++)
{
const CTxOut& prevout = GetOutputFor(vin[i], inputs);
if (prevout.scriptPubKey.IsPayToScriptHash())
@@ -1106,7 +1106,7 @@ bool CTransaction::ConnectInputs(MapPrevTx inputs,
{
int64 nValueIn = 0;
int64 nFees = 0;
- for (int i = 0; i < vin.size(); i++)
+ for (unsigned int i = 0; i < vin.size(); i++)
{
COutPoint prevout = vin[i].prevout;
assert(inputs.count(prevout.hash) > 0);
@@ -1185,7 +1185,7 @@ bool CTransaction::ClientConnectInputs()
{
LOCK(mempool.cs);
int64 nValueIn = 0;
- for (int i = 0; i < vin.size(); i++)
+ for (unsigned int i = 0; i < vin.size(); i++)
{
// Get prev tx from single transactions in memory
COutPoint prevout = vin[i].prevout;
@@ -1280,7 +1280,7 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex)
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());
+ unsigned int nTxPos = pindex->nBlockPos + ::GetSerializeSize(CBlock(), SER_DISK, CLIENT_VERSION) - 1 + GetSizeOfCompactSize(vtx.size());
map<uint256, CTxIndex> mapQueuedChanges;
int64 nFees = 0;
@@ -1292,7 +1292,7 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex)
return DoS(100, error("ConnectBlock() : too many sigops"));
CDiskTxPos posThisTx(pindex->nFile, pindex->nBlockPos, nTxPos);
- nTxPos += ::GetSerializeSize(tx, SER_DISK);
+ nTxPos += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
MapPrevTx mapInputs;
if (!tx.IsCoinBase())
@@ -1397,7 +1397,7 @@ bool static Reorganize(CTxDB& txdb, CBlockIndex* pindexNew)
// Connect longer branch
vector<CTransaction> vDelete;
- for (int i = 0; i < vConnect.size(); i++)
+ for (unsigned int i = 0; i < vConnect.size(); i++)
{
CBlockIndex* pindex = vConnect[i];
CBlock block;
@@ -1622,7 +1622,7 @@ bool CBlock::CheckBlock() const
// that can be verified before saving an orphan block.
// Size limits
- if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(*this, SER_NETWORK) > MAX_BLOCK_SIZE)
+ if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE)
return DoS(100, error("CheckBlock() : size limits failed"));
// Check proof of work matches claimed amount
@@ -1636,7 +1636,7 @@ bool CBlock::CheckBlock() const
// First transaction must be coinbase, the rest must not be
if (vtx.empty() || !vtx[0].IsCoinBase())
return DoS(100, error("CheckBlock() : first tx is not coinbase"));
- for (int i = 1; i < vtx.size(); i++)
+ for (unsigned int i = 1; i < vtx.size(); i++)
if (vtx[i].IsCoinBase())
return DoS(100, error("CheckBlock() : more than one coinbase"));
@@ -1692,7 +1692,7 @@ bool CBlock::AcceptBlock()
return DoS(100, error("AcceptBlock() : rejected by checkpoint lockin at %d", nHeight));
// Write block to history file
- if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK)))
+ if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK, CLIENT_VERSION)))
return error("AcceptBlock() : out of disk space");
unsigned int nFile = -1;
unsigned int nBlockPos = 0;
@@ -1772,7 +1772,7 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock)
// Recursively process any orphan blocks that depended on this one
vector<uint256> vWorkQueue;
vWorkQueue.push_back(hash);
- for (int i = 0; i < vWorkQueue.size(); i++)
+ for (unsigned int i = 0; i < vWorkQueue.size(); i++)
{
uint256 hashPrev = vWorkQueue[i];
for (multimap<uint256, CBlock*>::iterator mi = mapOrphanBlocksByPrev.lower_bound(hashPrev);
@@ -1996,7 +1996,7 @@ void PrintBlockTree()
// put the main timechain first
vector<CBlockIndex*>& vNext = mapNext[pindex];
- for (int i = 0; i < vNext.size(); i++)
+ for (unsigned int i = 0; i < vNext.size(); i++)
{
if (vNext[i]->pnext)
{
@@ -2006,7 +2006,7 @@ void PrintBlockTree()
}
// iterate children
- for (int i = 0; i < vNext.size(); i++)
+ for (unsigned int i = 0; i < vNext.size(); i++)
vStack.push_back(make_pair(nCol+i, vNext[i]));
}
}
@@ -2137,15 +2137,20 @@ bool static AlreadyHave(CTxDB& txdb, const CInv& inv)
switch (inv.type)
{
case MSG_TX:
- {
- LOCK(mempool.cs);
- return mempool.exists(inv.hash) ||
+ {
+ bool txInMap = false;
+ {
+ LOCK(mempool.cs);
+ txInMap = (mempool.exists(inv.hash));
+ }
+ return txInMap ||
mapOrphanTransactions.count(inv.hash) ||
txdb.ContainsTx(inv.hash);
- }
+ }
case MSG_BLOCK:
- return mapBlockIndex.count(inv.hash) || mapOrphanBlocks.count(inv.hash);
+ return mapBlockIndex.count(inv.hash) ||
+ mapOrphanBlocks.count(inv.hash);
}
// Don't know what it is, just say we already got one
return true;
@@ -2192,7 +2197,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
CAddress addrFrom;
uint64 nNonce = 1;
vRecv >> pfrom->nVersion >> pfrom->nServices >> nTime >> addrMe;
- if (pfrom->nVersion < 209)
+ if (pfrom->nVersion < MIN_PROTO_VERSION)
{
// Since February 20, 2012, the protocol is initiated at version 209,
// and earlier versions are no longer supported
@@ -2242,7 +2247,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
}
// Get recent addresses
- if (pfrom->nVersion >= 31402 || addrman.size() < 1000)
+ if (pfrom->nVersion >= CADDR_TIME_VERSION || addrman.size() < 1000)
{
pfrom->PushMessage("getaddr");
pfrom->fGetAddr = true;
@@ -2259,7 +2264,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
// Ask the first connected node for block updates
static int nAskedForBlocks = 0;
if (!pfrom->fClient &&
- (pfrom->nVersion < 32000 || pfrom->nVersion >= 32400) &&
+ (pfrom->nVersion < NOBLKS_VERSION_START ||
+ pfrom->nVersion >= NOBLKS_VERSION_END) &&
(nAskedForBlocks < 1 || vNodes.size() <= 1))
{
nAskedForBlocks++;
@@ -2301,7 +2307,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
vRecv >> vAddr;
// Don't want addr from older versions unless seeding
- if (pfrom->nVersion < 31402 && addrman.size() > 1000)
+ if (pfrom->nVersion < CADDR_TIME_VERSION && addrman.size() > 1000)
return true;
if (vAddr.size() > 1000)
{
@@ -2338,7 +2344,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
multimap<uint256, CNode*> mapMix;
BOOST_FOREACH(CNode* pnode, vNodes)
{
- if (pnode->nVersion < 31402)
+ if (pnode->nVersion < CADDR_TIME_VERSION)
continue;
unsigned int nPointer;
memcpy(&nPointer, &pnode, sizeof(nPointer));
@@ -2369,7 +2375,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
}
CTxDB txdb("r");
- for (int nInv = 0; nInv < vInv.size(); nInv++)
+ for (unsigned int nInv = 0; nInv < vInv.size(); nInv++)
{
const CInv &inv = vInv[nInv];
@@ -2476,7 +2482,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
pfrom->PushInventory(CInv(MSG_BLOCK, pindex->GetBlockHash()));
CBlock block;
block.ReadFromDisk(pindex, true);
- nBytes += block.GetSerializeSize(SER_NETWORK);
+ nBytes += block.GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION);
if (--nLimit <= 0 || nBytes >= SendBufferSize()/2)
{
// When this block is requested, we'll send an inv that'll make them
@@ -2545,7 +2551,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
vWorkQueue.push_back(inv.hash);
// Recursively process any orphan transactions that depended on this one
- for (int i = 0; i < vWorkQueue.size(); i++)
+ for (unsigned int i = 0; i < vWorkQueue.size(); i++)
{
uint256 hashPrev = vWorkQueue[i];
for (multimap<uint256, CDataStream*>::iterator mi = mapOrphanTransactionsByPrev.lower_bound(hashPrev);
@@ -2660,6 +2666,23 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
else if (strCommand == "ping")
{
+ if (pfrom->nVersion > BIP0031_VERSION)
+ {
+ uint64 nonce = 0;
+ vRecv >> nonce;
+ // Echo the message back with the nonce. This allows for two useful features:
+ //
+ // 1) A remote node can quickly check if the connection is operational
+ // 2) Remote nodes can measure the latency of the network thread. If this node
+ // is overloaded it won't respond to pings quickly and the remote node can
+ // avoid sending us more work, like chain download requests.
+ //
+ // The nonce stops the remote getting confused between different pings: without
+ // it, if the remote node sends a ping once per second and this node takes 5
+ // seconds to respond to each, the 5th ping the remote sends would appear to
+ // return very quickly.
+ pfrom->PushMessage("pong", nonce);
+ }
}
@@ -2816,15 +2839,20 @@ bool ProcessMessages(CNode* pfrom)
bool SendMessages(CNode* pto, bool fSendTrickle)
{
- {
- LOCK(cs_main);
+ TRY_LOCK(cs_main, lockMain);
+ if (lockMain) {
// Don't send anything until we get their version message
if (pto->nVersion == 0)
return true;
- // Keep-alive ping
- if (pto->nLastSend && GetTime() - pto->nLastSend > 30 * 60 && pto->vSend.empty())
- pto->PushMessage("ping");
+ // Keep-alive ping. We send a nonce of zero because we don't use it anywhere
+ // right now.
+ if (pto->nLastSend && GetTime() - pto->nLastSend > 30 * 60 && pto->vSend.empty()) {
+ if (pto->nVersion > BIP0031_VERSION)
+ pto->PushMessage("ping", 0);
+ else
+ pto->PushMessage("ping");
+ }
// Resend wallet transactions that haven't gotten in a block yet
ResendWalletTransactions();
@@ -3147,7 +3175,7 @@ CBlock* CreateNewBlock(CReserveKey& reservekey)
}
// Priority is sum(valuein * age) / txsize
- dPriority /= ::GetSerializeSize(tx, SER_NETWORK);
+ dPriority /= ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
if (porphan)
porphan->dPriority = dPriority;
@@ -3176,7 +3204,7 @@ CBlock* CreateNewBlock(CReserveKey& reservekey)
mapPriority.erase(mapPriority.begin());
// Size limits
- unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK);
+ unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
if (nBlockSize + nTxSize >= MAX_BLOCK_SIZE_GEN)
continue;
@@ -3303,7 +3331,7 @@ void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash
FormatHashBlocks(&tmp.hash1, sizeof(tmp.hash1));
// Byte swap all the input buffer
- for (int i = 0; i < sizeof(tmp)/4; i++)
+ for (unsigned int i = 0; i < sizeof(tmp)/4; i++)
((unsigned int*)&tmp)[i] = ByteReverse(((unsigned int*)&tmp)[i]);
// Precalc the first half of the first hash, which stays constant
@@ -3428,7 +3456,7 @@ void static BitcoinMiner(CWallet *pwallet)
// Check if something found
if (nNonceFound != -1)
{
- for (int i = 0; i < sizeof(hash)/4; i++)
+ for (unsigned int i = 0; i < sizeof(hash)/4; i++)
((unsigned int*)&hash)[i] = ByteReverse(((unsigned int*)&hash)[i]);
if (hash <= hashTarget)