// Copyright (c) 2009-2010 Satoshi Nakamoto
// 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.
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
#include "headers.h"
#include "checkpoints.h"
#include "db.h"
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);
if (!Solver(prevScript, whichType, vSolutions))
return false;
int nArgsExpected = ScriptSigArgsExpected(whichType, vSolutions);
+ if (nArgsExpected < 0)
+ return false;
// Transactions with extra stuff in their scriptSigs are
// non-standard. Note that this EvalScript() call will
return false;
if (whichType2 == TX_SCRIPTHASH)
return false;
- nArgsExpected += ScriptSigArgsExpected(whichType2, vSolutions2);
+
+ int tmpExpected;
+ tmpExpected = ScriptSigArgsExpected(whichType2, vSolutions2);
+ if (tmpExpected < 0)
+ return false;
+ nArgsExpected += tmpExpected;
}
- if (stack.size() != nArgsExpected)
+ if (stack.size() != (unsigned int)nArgsExpected)
return false;
}
// Check for conflicts with in-memory transactions
CTransaction* ptxOld = NULL;
- for (int i = 0; i < vin.size(); i++)
+ for (unsigned int i = 0; i < vin.size(); i++)
{
COutPoint outpoint = vin[i].prevout;
if (mapNextTx.count(outpoint))
return false;
if (!IsNewerThan(*ptxOld))
return false;
- for (int i = 0; i < vin.size(); i++)
+ for (unsigned int i = 0; i < vin.size(); i++)
{
COutPoint outpoint = vin[i].prevout;
if (!mapNextTx.count(outpoint) || mapNextTx[outpoint].ptx != ptxOld)
{
uint256 hash = GetHash();
mapTransactions[hash] = *this;
- for (int i = 0; i < vin.size(); i++)
+ for (unsigned int i = 0; i < vin.size(); i++)
mapNextTx[vin[i].prevout] = CInPoint(&mapTransactions[hash], i);
nTransactionsUpdated++;
++nPooledTx;
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))
}
// 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);
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;
}
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())
{
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);
CRITICAL_BLOCK(cs_mapTransactions)
{
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;
// 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;
+ }
}
+ }
- // 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);
+ // 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());
// 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;
{
uint256 hash = GetHash();
- txdb.TxnBegin();
+ if (!txdb.TxnBegin())
+ return error("SetBestChain() : TxnBegin failed");
+
if (pindexGenesisBlock == NULL && hash == hashGenesisBlock)
{
txdb.WriteHashBestChain(hash);
printf("SetBestChain() : ReadFromDisk failed\n");
break;
}
- txdb.TxnBegin();
+ if (!txdb.TxnBegin()) {
+ printf("SetBestChain() : TxnBegin 2 failed\n");
+ break;
+ }
// errors now are not fatal, we still did a reorganisation to a new chain in a valid way
if (!block.SetBestChainInner(txdb, pindex))
break;
pindexNew->bnChainWork = (pindexNew->pprev ? pindexNew->pprev->bnChainWork : 0) + pindexNew->GetBlockWork();
CTxDB txdb;
- txdb.TxnBegin();
+ if (!txdb.TxnBegin())
+ return false;
txdb.WriteBlockIndex(CDiskBlockIndex(pindexNew));
if (!txdb.TxnCommit())
return false;
// 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"));
if (!tx.CheckTransaction())
return DoS(tx.nDoS, error("CheckBlock() : CheckTransaction failed"));
+ // Check for duplicate txids. This is caught by ConnectInputs(),
+ // but catching it earlier avoids a potential DoS attack:
+ set<uint256> uniqueTx;
+ BOOST_FOREACH(const CTransaction& tx, vtx)
+ {
+ uniqueTx.insert(tx.GetHash());
+ }
+ if (uniqueTx.size() != vtx.size())
+ return DoS(100, error("CheckBlock() : duplicate transaction"));
+
int nSigOps = 0;
BOOST_FOREACH(const CTransaction& tx, vtx)
{
// 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);
// 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)
{
}
// 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]));
}
}
{
switch (inv.type)
{
- case MSG_TX: return mapTransactions.count(inv.hash) || mapOrphanTransactions.count(inv.hash) || txdb.ContainsTx(inv.hash);
+ case MSG_TX:
+ {
+ bool txInMap = false;
+ CRITICAL_BLOCK(cs_mapTransactions)
+ {
+ txInMap = (mapTransactions.count(inv.hash) != 0);
+ }
+ return txInMap ||
+ mapOrphanTransactions.count(inv.hash) ||
+ txdb.ContainsTx(inv.hash);
+ }
+
case MSG_BLOCK: return mapBlockIndex.count(inv.hash) || mapOrphanBlocks.count(inv.hash);
}
// Don't know what it is, just say we already got one
}
// 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;
}
return error("message inv size() = %d", vInv.size());
}
+ // find last block in inv vector
+ unsigned int nLastBlock = (unsigned int)(-1);
+ for (unsigned int nInv = 0; nInv < vInv.size(); nInv++) {
+ if (vInv[vInv.size() - 1 - nInv].type == MSG_BLOCK)
+ nLastBlock = vInv.size() - 1 - nInv;
+ }
CTxDB txdb("r");
- BOOST_FOREACH(const CInv& inv, vInv)
+ for (unsigned 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");
+ // 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 && nInv == nLastBlock) {
+ // bypass mapAskFor, and send request directly; it must go through.
+ std::vector<CInv> vGetData(1,inv);
+ pfrom->PushMessage("getdata", vGetData);
+ }
+
if (!fAlreadyHave)
pfrom->AskFor(inv);
else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash))
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);
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);
}
bool SendMessages(CNode* pto, bool fSendTrickle)
{
- CRITICAL_BLOCK(cs_main)
+ TRY_CRITICAL_BLOCK(cs_main)
{
// Don't send anything until we get their version message
if (pto->nVersion == 0)
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
//
dPriority += (double)nValueIn * nConf;
if (fDebug && GetBoolArg("-printpriority"))
- printf("priority nValueIn=%-12I64d nConf=%-5d dPriority=%-20.1f\n", nValueIn, nConf, dPriority);
+ printf("priority nValueIn=%-12"PRI64d" nConf=%-5d dPriority=%-20.1f\n", nValueIn, nConf, dPriority);
}
// Priority is sum(valuein * age) / txsize
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
// 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)