aboutsummaryrefslogtreecommitdiff
path: root/src/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.cpp')
-rw-r--r--src/main.cpp623
1 files changed, 412 insertions, 211 deletions
diff --git a/src/main.cpp b/src/main.cpp
index fc57713129..5acf5b97d4 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -8,7 +8,7 @@
#include "db.h"
#include "net.h"
#include "init.h"
-#include "cryptopp/sha.h"
+#include <boost/algorithm/string/replace.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
@@ -19,6 +19,11 @@ using namespace boost;
// Global state
//
+// Name of client reported in the 'version' message. Report the same name
+// for both bitcoind and bitcoin-qt, to make it harder for attackers to
+// target servers or GUI users specifically.
+const std::string CLIENT_NAME("Satoshi");
+
CCriticalSection cs_setpwalletRegistered;
set<CWallet*> setpwalletRegistered;
@@ -32,7 +37,6 @@ map<COutPoint, CInPoint> mapNextTx;
map<uint256, CBlockIndex*> mapBlockIndex;
uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f");
static CBigNum bnProofOfWorkLimit(~uint256(0) >> 32);
-const int nInitialBlockThreshold = 120; // Regard blocks up until N-threshold as "initial download"
CBlockIndex* pindexGenesisBlock = NULL;
int nBestHeight = -1;
CBigNum bnBestChainWork = 0;
@@ -41,32 +45,24 @@ uint256 hashBestChain = 0;
CBlockIndex* pindexBest = NULL;
int64 nTimeBestReceived = 0;
+CMedianFilter<int> cPeerBlockCounts(5, 0); // Amount of blocks that other nodes claim to have
+
map<uint256, CBlock*> mapOrphanBlocks;
multimap<uint256, CBlock*> mapOrphanBlocksByPrev;
map<uint256, CDataStream*> mapOrphanTransactions;
map<uint256, map<uint256, CDataStream*> > mapOrphanTransactionsByPrev;
+// Constant stuff for coinbase transactions we create:
+CScript COINBASE_FLAGS;
+
+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
-
-
-
-
@@ -75,6 +71,9 @@ int fUseUPnP = false;
// dispatching functions
//
+// These functions dispatch to one or all registered wallets
+
+
void RegisterWallet(CWallet* pwalletIn)
{
CRITICAL_BLOCK(cs_setpwalletRegistered)
@@ -91,6 +90,7 @@ void UnregisterWallet(CWallet* pwalletIn)
}
}
+// check whether the passed transaction is from us
bool static IsFromMe(CTransaction& tx)
{
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
@@ -99,6 +99,7 @@ bool static IsFromMe(CTransaction& tx)
return false;
}
+// get the wallet transaction with the given hash (if it exists)
bool static GetTransaction(const uint256& hashTx, CWalletTx& wtx)
{
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
@@ -107,42 +108,49 @@ bool static GetTransaction(const uint256& hashTx, CWalletTx& wtx)
return false;
}
+// erases transaction with the given hash from all wallets
void static EraseFromWallets(uint256 hash)
{
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
pwallet->EraseFromWallet(hash);
}
+// make sure all wallets know about the given transaction, in the given block
void static SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL, bool fUpdate = false)
{
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
pwallet->AddToWalletIfInvolvingMe(tx, pblock, fUpdate);
}
+// notify wallets about a new best chain
void static SetBestChain(const CBlockLocator& loc)
{
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
pwallet->SetBestChain(loc);
}
+// notify wallets about an updated transaction
void static UpdatedTransaction(const uint256& hashTx)
{
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
pwallet->UpdatedTransaction(hashTx);
}
+// dump all wallets
void static PrintWallets(const CBlock& block)
{
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
pwallet->PrintWallet(block);
}
+// notify wallets about an incoming inventory (for request counts)
void static Inventory(const uint256& hash)
{
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
pwallet->Inventory(hash);
}
+// ask wallets to resend their transactions
void static ResendWalletTransactions()
{
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
@@ -267,6 +275,103 @@ bool CTransaction::ReadFromDisk(COutPoint prevout)
return ReadFromDisk(txdb, prevout, txindex);
}
+bool CTransaction::IsStandard() const
+{
+ BOOST_FOREACH(const CTxIn& txin, vin)
+ {
+ // Biggest 'standard' txin is a 3-signature 3-of-3 CHECKMULTISIG
+ // pay-to-script-hash, which is 3 ~80-byte signatures, 3
+ // ~65-byte public keys, plus a few script ops.
+ if (txin.scriptSig.size() > 500)
+ return false;
+ if (!txin.scriptSig.IsPushOnly())
+ return false;
+ }
+ BOOST_FOREACH(const CTxOut& txout, vout)
+ if (!::IsStandard(txout.scriptPubKey))
+ return false;
+ return true;
+}
+
+//
+// Check transaction inputs, and make sure any
+// pay-to-script-hash transactions are evaluating IsStandard scripts
+//
+// Why bother? To avoid denial-of-service attacks; an attacker
+// can submit a standard HASH... OP_EQUAL transaction,
+// which will get accepted into blocks. The redemption
+// script can be anything; an attacker could use a very
+// expensive-to-check-upon-redemption script like:
+// DUP CHECKSIG DROP ... repeated 100 times... OP_1
+//
+bool CTransaction::AreInputsStandard(const MapPrevTx& mapInputs) const
+{
+ if (IsCoinBase())
+ return true; // Coinbases don't use vin normally
+
+ for (unsigned int i = 0; i < vin.size(); i++)
+ {
+ const CTxOut& prev = GetOutputFor(vin[i], mapInputs);
+
+ vector<vector<unsigned char> > vSolutions;
+ txnouttype whichType;
+ // get the scriptPubKey corresponding to this input:
+ const CScript& prevScript = prev.scriptPubKey;
+ 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
+ // be quick, because if there are any operations
+ // beside "push data" in the scriptSig the
+ // IsStandard() call returns false
+ vector<vector<unsigned char> > stack;
+ if (!EvalScript(stack, vin[i].scriptSig, *this, i, 0))
+ return false;
+
+ if (whichType == TX_SCRIPTHASH)
+ {
+ if (stack.empty())
+ return false;
+ CScript subscript(stack.back().begin(), stack.back().end());
+ vector<vector<unsigned char> > vSolutions2;
+ txnouttype whichType2;
+ if (!Solver(subscript, whichType2, vSolutions2))
+ return false;
+ if (whichType2 == TX_SCRIPTHASH)
+ return false;
+
+ int tmpExpected;
+ tmpExpected = ScriptSigArgsExpected(whichType2, vSolutions2);
+ if (tmpExpected < 0)
+ return false;
+ nArgsExpected += tmpExpected;
+ }
+
+ if (stack.size() != (unsigned int)nArgsExpected)
+ return false;
+ }
+
+ return true;
+}
+
+int
+CTransaction::GetLegacySigOpCount() const
+{
+ int nSigOps = 0;
+ BOOST_FOREACH(const CTxIn& txin, vin)
+ {
+ nSigOps += txin.scriptSig.GetSigOpCount(false);
+ }
+ BOOST_FOREACH(const CTxOut& txout, vout)
+ {
+ nSigOps += txout.scriptPubKey.GetSigOpCount(false);
+ }
+ return nSigOps;
+}
int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
@@ -330,24 +435,24 @@ bool CTransaction::CheckTransaction() const
{
// Basic checks that don't depend on any context
if (vin.empty())
- return error("CTransaction::CheckTransaction() : vin empty");
+ return DoS(10, error("CTransaction::CheckTransaction() : vin empty"));
if (vout.empty())
- return error("CTransaction::CheckTransaction() : vout empty");
+ return DoS(10, error("CTransaction::CheckTransaction() : vout empty"));
// Size limits
if (::GetSerializeSize(*this, SER_NETWORK) > MAX_BLOCK_SIZE)
- return error("CTransaction::CheckTransaction() : size limits failed");
+ return DoS(100, error("CTransaction::CheckTransaction() : size limits failed"));
// Check for negative or overflow output values
int64 nValueOut = 0;
BOOST_FOREACH(const CTxOut& txout, vout)
{
if (txout.nValue < 0)
- return error("CTransaction::CheckTransaction() : txout.nValue negative");
+ return DoS(100, error("CTransaction::CheckTransaction() : txout.nValue negative"));
if (txout.nValue > MAX_MONEY)
- return error("CTransaction::CheckTransaction() : txout.nValue too high");
+ return DoS(100, error("CTransaction::CheckTransaction() : txout.nValue too high"));
nValueOut += txout.nValue;
if (!MoneyRange(nValueOut))
- return error("CTransaction::CheckTransaction() : txout total out of range");
+ return DoS(100, error("CTransaction::CheckTransaction() : txout total out of range"));
}
// Check for duplicate inputs
@@ -362,13 +467,13 @@ bool CTransaction::CheckTransaction() const
if (IsCoinBase())
{
if (vin[0].scriptSig.size() < 2 || vin[0].scriptSig.size() > 100)
- return error("CTransaction::CheckTransaction() : coinbase script size");
+ return DoS(100, error("CTransaction::CheckTransaction() : coinbase script size"));
}
else
{
BOOST_FOREACH(const CTxIn& txin, vin)
if (txin.prevout.IsNull())
- return error("CTransaction::CheckTransaction() : prevout is null");
+ return DoS(10, error("CTransaction::CheckTransaction() : prevout is null"));
}
return true;
@@ -384,7 +489,7 @@ bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMi
// Coinbase is only valid in a block, not as a loose transaction
if (IsCoinBase())
- return error("AcceptToMemoryPool() : coinbase as individual tx");
+ return DoS(100, error("AcceptToMemoryPool() : coinbase as individual tx"));
// To help v0.1.5 clients who would see it as a negative number
if ((int64)nLockTime > std::numeric_limits<int>::max())
@@ -445,19 +550,19 @@ bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMi
return error("AcceptToMemoryPool() : FetchInputs failed %s", hash.ToString().substr(0,10).c_str());
}
- // Safety limits
- unsigned int nSize = ::GetSerializeSize(*this, SER_NETWORK);
- // Checking ECDSA signatures is a CPU bottleneck, so to avoid denial-of-service
- // attacks disallow transactions with more than one SigOp per 34 bytes.
- // 34 bytes because a TxOut is:
- // 20-byte address + 8 byte bitcoin amount + 5 bytes of ops + 1 byte script length
- if (GetSigOpCount() > nSize / 34 || nSize < 100)
- return error("AcceptToMemoryPool() : nonstandard transaction");
+ // Check for non-standard pay-to-script-hash in inputs
+ if (!AreInputsStandard(mapInputs) && !fTestNet)
+ return error("AcceptToMemoryPool() : nonstandard transaction input");
+
+ // Note: if you modify this code to accept non-standard transactions, then
+ // you should add code here to check that the transaction does a
+ // reasonable number of ECDSA signature verifications.
int64 nFees = GetValueIn(mapInputs)-GetValueOut();
+ unsigned int nSize = ::GetSerializeSize(*this, SER_NETWORK);
// Don't accept it if it can't get into a block
- if (nFees < GetMinFee(1000, true, true))
+ if (nFees < GetMinFee(1000, true, GMF_RELAY))
return error("AcceptToMemoryPool() : not enough fees");
// Continuously rate-limit free transactions
@@ -519,8 +624,11 @@ bool CTransaction::AcceptToMemoryPool(bool fCheckInputs, bool* pfMissingInputs)
return AcceptToMemoryPool(txdb, fCheckInputs, pfMissingInputs);
}
+uint64 nPooledTx = 0;
+
bool CTransaction::AddToMemoryPoolUnchecked()
{
+ printf("AcceptToMemoryPoolUnchecked(): size %lu\n", mapTransactions.size());
// Add to memory pool without checking anything. Don't call this directly,
// call AcceptToMemoryPool to properly check the transaction first.
CRITICAL_BLOCK(cs_mapTransactions)
@@ -530,6 +638,7 @@ bool CTransaction::AddToMemoryPoolUnchecked()
for (unsigned int i = 0; i < vin.size(); i++)
mapNextTx[vin[i].prevout] = CInPoint(&mapTransactions[hash], i);
nTransactionsUpdated++;
+ ++nPooledTx;
}
return true;
}
@@ -540,10 +649,15 @@ bool CTransaction::RemoveFromMemoryPool()
// Remove transaction from memory pool
CRITICAL_BLOCK(cs_mapTransactions)
{
- BOOST_FOREACH(const CTxIn& txin, vin)
- mapNextTx.erase(txin.prevout);
- mapTransactions.erase(GetHash());
- nTransactionsUpdated++;
+ uint256 hash = GetHash();
+ if (mapTransactions.count(hash))
+ {
+ BOOST_FOREACH(const CTxIn& txin, vin)
+ mapNextTx.erase(txin.prevout);
+ mapTransactions.erase(hash);
+ nTransactionsUpdated++;
+ --nPooledTx;
+ }
}
return true;
}
@@ -553,7 +667,7 @@ bool CTransaction::RemoveFromMemoryPool()
-int CMerkleTx::GetDepthInMainChain(int& nHeightRet) const
+int CMerkleTx::GetDepthInMainChain(CBlockIndex* &pindexRet) const
{
if (hashBlock == 0 || nIndex == -1)
return 0;
@@ -574,7 +688,7 @@ int CMerkleTx::GetDepthInMainChain(int& nHeightRet) const
fMerkleVerified = true;
}
- nHeightRet = pindex->nHeight;
+ pindexRet = pindex;
return pindexBest->nHeight - pindex->nHeight + 1;
}
@@ -804,9 +918,15 @@ bool CheckProofOfWork(uint256 hash, unsigned int nBits)
return true;
}
+// Return maximum amount of blocks that other nodes claim to have
+int GetNumBlocksOfPeers()
+{
+ return std::max(cPeerBlockCounts.median(), Checkpoints::GetTotalBlocksEstimate());
+}
+
bool IsInitialBlockDownload()
{
- if (pindexBest == NULL || nBestHeight < (Checkpoints::GetTotalBlocksEstimate()-nInitialBlockThreshold))
+ if (pindexBest == NULL || nBestHeight < Checkpoints::GetTotalBlocksEstimate())
return true;
static int64 nLastUpdate;
static CBlockIndex* pindexLastBest;
@@ -956,7 +1076,7 @@ bool CTransaction::FetchInputs(CTxDB& txdb, const map<uint256, CTxIndex>& mapTes
// Revisit this if/when transaction replacement is implemented and allows
// adding inputs:
fInvalid = true;
- return error("FetchInputs() : %s prevout.n out of range %d %d %d prev tx %s\n%s", GetHash().ToString().substr(0,10).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,10).c_str(), txPrev.ToString().c_str());
+ return DoS(100, error("FetchInputs() : %s prevout.n out of range %d %d %d prev tx %s\n%s", GetHash().ToString().substr(0,10).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,10).c_str(), txPrev.ToString().c_str()));
}
}
@@ -1025,7 +1145,7 @@ bool CTransaction::ConnectInputs(MapPrevTx inputs,
CTransaction& txPrev = inputs[prevout.hash].second;
if (prevout.n >= txPrev.vout.size() || prevout.n >= txindex.vSpent.size())
- return error("ConnectInputs() : %s prevout.n out of range %d %d %d prev tx %s\n%s", GetHash().ToString().substr(0,10).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,10).c_str(), txPrev.ToString().c_str());
+ return DoS(100, error("ConnectInputs() : %s prevout.n out of range %d %d %d prev tx %s\n%s", GetHash().ToString().substr(0,10).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,10).c_str(), txPrev.ToString().c_str()));
// If prev is coinbase, check that it's matured
if (txPrev.IsCoinBase())
@@ -1036,7 +1156,7 @@ bool CTransaction::ConnectInputs(MapPrevTx inputs,
// Check for negative or overflow input values
nValueIn += txPrev.vout[prevout.n].nValue;
if (!MoneyRange(txPrev.vout[prevout.n].nValue) || !MoneyRange(nValueIn))
- return error("ConnectInputs() : txin values out of range");
+ return DoS(100, error("ConnectInputs() : txin values out of range"));
}
// The first loop above does all the inexpensive checks.
@@ -1050,19 +1170,26 @@ bool CTransaction::ConnectInputs(MapPrevTx inputs,
CTransaction& txPrev = inputs[prevout.hash].second;
// Check for conflicts (double-spend)
+ // This doesn't trigger the DoS code on purpose; if it did, it would make it easier
+ // for an attacker to attempt to split the network.
if (!txindex.vSpent[prevout.n].IsNull())
return fMiner ? false : error("ConnectInputs() : %s prev tx already used at %s", GetHash().ToString().substr(0,10).c_str(), txindex.vSpent[prevout.n].ToString().c_str());
- // Verify signature
- if (!VerifySignature(txPrev, *this, i, fStrictPayToScriptHash, 0))
+ // Skip ECDSA signature verification when connecting blocks (fBlock=true)
+ // before the last blockchain checkpoint. This is safe because block merkle hashes are
+ // still computed and checked, and any change will be caught at the next checkpoint.
+ if (!(fBlock && (nBestHeight < Checkpoints::GetTotalBlocksEstimate())))
{
- // only during transition phase for P2SH: do not invoke (external)
- // 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());
+ // 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 error("ConnectInputs() : %s 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
@@ -1076,15 +1203,15 @@ bool CTransaction::ConnectInputs(MapPrevTx inputs,
}
if (nValueIn < GetValueOut())
- return error("ConnectInputs() : %s value in < value out", GetHash().ToString().substr(0,10).c_str());
+ return DoS(100, error("ConnectInputs() : %s value in < value out", GetHash().ToString().substr(0,10).c_str()));
// Tally transaction fees
int64 nTxFee = nValueIn - GetValueOut();
if (nTxFee < 0)
- return error("ConnectInputs() : %s nTxFee < 0", GetHash().ToString().substr(0,10).c_str());
+ return DoS(100, error("ConnectInputs() : %s nTxFee < 0", GetHash().ToString().substr(0,10).c_str()));
nFees += nTxFee;
if (!MoneyRange(nFees))
- return error("ConnectInputs() : nFees out of range");
+ return DoS(100, error("ConnectInputs() : nFees out of range"));
}
return true;
@@ -1189,9 +1316,9 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex)
}
}
- // P2SH didn't become active until Apr 1 2012 (Feb 15 on testnet)
- int64 nEvalSwitchTime = fTestNet ? 1329264000 : 1333238400;
- 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());
@@ -1201,17 +1328,17 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex)
int nSigOps = 0;
BOOST_FOREACH(CTransaction& tx, vtx)
{
- nSigOps += tx.GetSigOpCount();
+ nSigOps += tx.GetLegacySigOpCount();
if (nSigOps > MAX_BLOCK_SIGOPS)
- return error("ConnectBlock() : too many sigops");
+ return DoS(100, error("ConnectBlock() : too many sigops"));
CDiskTxPos posThisTx(pindex->nFile, pindex->nBlockPos, nTxPos);
nTxPos += ::GetSerializeSize(tx, SER_DISK);
- bool fInvalid;
MapPrevTx mapInputs;
if (!tx.IsCoinBase())
{
+ bool fInvalid;
if (!tx.FetchInputs(txdb, mapQueuedChanges, true, false, mapInputs, fInvalid))
return false;
@@ -1222,7 +1349,7 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex)
// an incredibly-expensive-to-validate block.
nSigOps += tx.GetP2SHSigOpCount(mapInputs);
if (nSigOps > MAX_BLOCK_SIGOPS)
- return error("ConnectBlock() : too many sigops");
+ return DoS(100, error("ConnectBlock() : too many sigops"));
}
nFees += tx.GetValueIn(mapInputs)-tx.GetValueOut();
@@ -1359,6 +1486,39 @@ bool static Reorganize(CTxDB& txdb, CBlockIndex* pindexNew)
}
+static void
+runCommand(std::string strCommand)
+{
+ int nErr = ::system(strCommand.c_str());
+ if (nErr)
+ 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();
@@ -1375,36 +1535,58 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew)
}
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 further blocks
+ BOOST_REVERSE_FOREACH(CBlockIndex *pindex, vpindexSecondary)
+ {
+ CBlock block;
+ if (!block.ReadFromDisk(pindex))
+ {
+ printf("SetBestChain() : ReadFromDisk failed\n");
+ break;
+ }
+ 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;
+ }
}
// Update best block in wallet (so we can detect restored wallets)
- if (!IsInitialBlockDownload())
+ bool fIsInitialDownload = IsInitialBlockDownload();
+ if (!fIsInitialDownload)
{
const CBlockLocator locator(pindexNew);
::SetBestChain(locator);
@@ -1419,6 +1601,14 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew)
nTransactionsUpdated++;
printf("SetBestChain: new best=%s height=%d work=%s\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, bnBestChainWork.ToString().c_str());
+ std::string strCmd = GetArg("-blocknotify", "");
+
+ if (!fIsInitialDownload && !strCmd.empty())
+ {
+ boost::replace_all(strCmd, "%s", hashBestChain.GetHex());
+ boost::thread t(runCommand, strCmd); // thread runs free
+ }
+
return true;
}
@@ -1480,11 +1670,11 @@ bool CBlock::CheckBlock() const
// Size limits
if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(*this, SER_NETWORK) > MAX_BLOCK_SIZE)
- return error("CheckBlock() : size limits failed");
+ return DoS(100, error("CheckBlock() : size limits failed"));
// Check proof of work matches claimed amount
if (!CheckProofOfWork(GetHash(), nBits))
- return error("CheckBlock() : proof of work failed");
+ return DoS(50, error("CheckBlock() : proof of work failed"));
// Check timestamp
if (GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60)
@@ -1492,15 +1682,15 @@ bool CBlock::CheckBlock() const
// First transaction must be coinbase, the rest must not be
if (vtx.empty() || !vtx[0].IsCoinBase())
- return error("CheckBlock() : first tx is not coinbase");
+ return DoS(100, error("CheckBlock() : first tx is not coinbase"));
for (unsigned int i = 1; i < vtx.size(); i++)
if (vtx[i].IsCoinBase())
- return error("CheckBlock() : more than one coinbase");
+ return DoS(100, error("CheckBlock() : more than one coinbase"));
// Check transactions
BOOST_FOREACH(const CTransaction& tx, vtx)
if (!tx.CheckTransaction())
- return error("CheckBlock() : CheckTransaction failed");
+ 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:
@@ -1510,15 +1700,19 @@ bool CBlock::CheckBlock() const
uniqueTx.insert(tx.GetHash());
}
if (uniqueTx.size() != vtx.size())
- return error("CheckBlock() : duplicate transaction");
+ return DoS(100, error("CheckBlock() : duplicate transaction"));
- // Check that it's not full of nonstandard transactions
- if (GetSigOpCount() > MAX_BLOCK_SIGOPS)
- return error("CheckBlock() : out-of-bounds SigOpCount");
+ int nSigOps = 0;
+ BOOST_FOREACH(const CTransaction& tx, vtx)
+ {
+ nSigOps += tx.GetLegacySigOpCount();
+ }
+ if (nSigOps > MAX_BLOCK_SIGOPS)
+ return DoS(100, error("CheckBlock() : out-of-bounds SigOpCount"));
// Check merkle root
if (hashMerkleRoot != BuildMerkleTree())
- return error("CheckBlock() : hashMerkleRoot mismatch");
+ return DoS(100, error("CheckBlock() : hashMerkleRoot mismatch"));
return true;
}
@@ -1533,13 +1727,13 @@ bool CBlock::AcceptBlock()
// Get prev block index
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashPrevBlock);
if (mi == mapBlockIndex.end())
- return error("AcceptBlock() : prev block not found");
+ return DoS(10, error("AcceptBlock() : prev block not found"));
CBlockIndex* pindexPrev = (*mi).second;
int nHeight = pindexPrev->nHeight+1;
// Check proof of work
if (nBits != GetNextWorkRequired(pindexPrev, this))
- return error("AcceptBlock() : incorrect proof of work");
+ return DoS(100, error("AcceptBlock() : incorrect proof of work"));
// Check timestamp against prev
if (GetBlockTime() <= pindexPrev->GetMedianTimePast())
@@ -1548,11 +1742,11 @@ bool CBlock::AcceptBlock()
// Check that all transactions are finalized
BOOST_FOREACH(const CTransaction& tx, vtx)
if (!tx.IsFinal(nHeight, GetBlockTime()))
- return error("AcceptBlock() : contains a non-final transaction");
+ return DoS(10, error("AcceptBlock() : contains a non-final transaction"));
// Check that the block chain matches the known block chain up to a checkpoint
if (!Checkpoints::CheckBlock(nHeight, hash))
- return error("AcceptBlock() : rejected by checkpoint lockin at %d", nHeight);
+ return DoS(100, error("AcceptBlock() : rejected by checkpoint lockin at %d", nHeight));
// Enforce block.nVersion=2 rule that the coinbase starts with serialized block height
if (nVersion > 1)
@@ -1600,7 +1794,7 @@ bool CBlockIndex::IsSuperMajority(int minVersion, const CBlockIndex* pstart, uns
return (nFound >= nRequired);
}
-bool static ProcessBlock(CNode* pfrom, CBlock* pblock)
+bool ProcessBlock(CNode* pfrom, CBlock* pblock)
{
// Check for duplicate
uint256 hash = pblock->GetHash();
@@ -1620,6 +1814,8 @@ bool static ProcessBlock(CNode* pfrom, CBlock* pblock)
int64 deltaTime = pblock->GetBlockTime() - pcheckpoint->nTime;
if (deltaTime < 0)
{
+ if (pfrom)
+ pfrom->Misbehaving(100);
return error("ProcessBlock() : block with timestamp before last checkpoint");
}
CBigNum bnNewBlock;
@@ -1628,6 +1824,8 @@ bool static ProcessBlock(CNode* pfrom, CBlock* pblock)
bnRequired.SetCompact(ComputeMinWork(pcheckpoint->nBits, deltaTime));
if (bnNewBlock > bnRequired)
{
+ if (pfrom)
+ pfrom->Misbehaving(100);
return error("ProcessBlock() : block with too little proof-of-work");
}
}
@@ -1693,7 +1891,7 @@ bool CheckDiskSpace(uint64 nAdditionalBytes)
strMiscWarning = strMessage;
printf("*** %s\n", strMessage.c_str());
ThreadSafeMessageBox(strMessage, "Bitcoin", wxOK | wxICON_EXCLAMATION);
- CreateThread(Shutdown, NULL);
+ StartShutdown();
return false;
}
return true;
@@ -2047,7 +2245,7 @@ unsigned char pchMessageStart[4] = { 0xf9, 0xbe, 0xb4, 0xd9 };
bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
{
- static map<unsigned int, vector<unsigned char> > mapReuseKey;
+ static map<CService, vector<unsigned char> > mapReuseKey;
RandAddSeedPerfmon();
if (fDebug) {
printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
@@ -2067,25 +2265,34 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
{
// Each connection can only send one version message
if (pfrom->nVersion != 0)
+ {
+ pfrom->Misbehaving(1);
return false;
+ }
int64 nTime;
CAddress addrMe;
CAddress addrFrom;
uint64 nNonce = 1;
vRecv >> pfrom->nVersion >> pfrom->nServices >> nTime >> addrMe;
+ if (pfrom->nVersion < 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;
+ return false;
+ }
+
if (pfrom->nVersion == 10300)
pfrom->nVersion = 300;
- if (pfrom->nVersion >= 106 && !vRecv.empty())
+ if (!vRecv.empty())
vRecv >> addrFrom >> nNonce;
- if (pfrom->nVersion >= 106 && !vRecv.empty())
+ if (!vRecv.empty())
vRecv >> pfrom->strSubVer;
- if (pfrom->nVersion >= 209 && !vRecv.empty())
+ if (!vRecv.empty())
vRecv >> pfrom->nStartingHeight;
- if (pfrom->nVersion == 0)
- return false;
-
// Disconnect if we connected to ourself
if (nNonce == nLocalHostNonce && nNonce > 1)
{
@@ -2100,19 +2307,17 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
pfrom->fClient = !(pfrom->nServices & NODE_NETWORK);
- AddTimeData(pfrom->addr.ip, nTime);
+ AddTimeData(pfrom->addr, nTime);
// Change version
- if (pfrom->nVersion >= 209)
- pfrom->PushMessage("verack");
- pfrom->vSend.SetVersion(min(pfrom->nVersion, VERSION));
- if (pfrom->nVersion < 209)
- pfrom->vRecv.SetVersion(min(pfrom->nVersion, VERSION));
+ pfrom->PushMessage("verack");
+ pfrom->vSend.SetVersion(min(pfrom->nVersion, PROTOCOL_VERSION));
if (!pfrom->fInbound)
{
// Advertise our address
- if (addrLocalHost.IsRoutable() && !fUseProxy)
+ if (!fNoListen && !fUseProxy && addrLocalHost.IsRoutable() &&
+ !IsInitialBlockDownload())
{
CAddress addr(addrLocalHost);
addr.nTime = GetAdjustedTime();
@@ -2120,11 +2325,18 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
}
// 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
@@ -2145,19 +2357,22 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
pfrom->fSuccessfullyConnected = true;
printf("version message: version %d, blocks=%d\n", pfrom->nVersion, pfrom->nStartingHeight);
+
+ cPeerBlockCounts.input(pfrom->nStartingHeight);
}
else if (pfrom->nVersion == 0)
{
// Must have a version message before anything else
+ pfrom->Misbehaving(1);
return false;
}
else if (strCommand == "verack")
{
- pfrom->vRecv.SetVersion(min(pfrom->nVersion, VERSION));
+ pfrom->vRecv.SetVersion(min(pfrom->nVersion, PROTOCOL_VERSION));
}
@@ -2167,16 +2382,15 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
vRecv >> vAddr;
// Don't want addr from older versions unless seeding
- if (pfrom->nVersion < 209)
- return true;
- if (pfrom->nVersion < 31402 && mapAddresses.size() > 1000)
+ if (pfrom->nVersion < 31402 && addrman.size() > 1000)
return true;
if (vAddr.size() > 1000)
+ {
+ pfrom->Misbehaving(20);
return error("message addr size() = %d", vAddr.size());
+ }
// Store the new addresses
- CAddrDB addrDB;
- addrDB.TxnBegin();
int64 nNow = GetAdjustedTime();
int64 nSince = nNow - 10 * 60;
BOOST_FOREACH(CAddress& addr, vAddr)
@@ -2188,7 +2402,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
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())
{
@@ -2200,7 +2413,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
static uint256 hashSalt;
if (hashSalt == 0)
RAND_bytes((unsigned char*)&hashSalt, sizeof(hashSalt));
- uint256 hashRand = hashSalt ^ (((int64)addr.ip)<<32) ^ ((GetTime()+addr.ip)/(24*60*60));
+ int64 hashAddr = addr.GetHash();
+ uint256 hashRand = hashSalt ^ (hashAddr<<32) ^ ((GetTime()+hashAddr)/(24*60*60));
hashRand = Hash(BEGIN(hashRand), END(hashRand));
multimap<uint256, CNode*> mapMix;
BOOST_FOREACH(CNode* pnode, vNodes)
@@ -2219,7 +2433,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
}
}
}
- 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;
}
@@ -2230,7 +2444,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
vector<CInv> vInv;
vRecv >> vInv;
if (vInv.size() > 50000)
+ {
+ pfrom->Misbehaving(20);
return error("message inv size() = %d", vInv.size());
+ }
// find last block in inv vector
unsigned int nLastBlock = (unsigned int)(-1);
@@ -2241,7 +2458,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];
@@ -2278,7 +2495,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
vector<CInv> vInv;
vRecv >> vInv;
if (vInv.size() > 50000)
+ {
+ pfrom->Misbehaving(20);
return error("message getdata size() = %d", vInv.size());
+ }
BOOST_FOREACH(const CInv& inv, vInv)
{
@@ -2464,6 +2684,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
if (nEvicted > 0)
printf("mapOrphan overflow, removed %d tx\n", nEvicted);
}
+ if (tx.nDoS) pfrom->Misbehaving(tx.nDoS);
}
@@ -2480,30 +2701,16 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
if (ProcessBlock(pfrom, &block))
mapAlreadyAskedFor.erase(inv);
+ if (block.nDoS) pfrom->Misbehaving(block.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);
}
@@ -2524,12 +2731,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
/// we have a chance to check the order here
// Keep giving the same key to the same ip until they use it
- if (!mapReuseKey.count(pfrom->addr.ip))
- pwalletMain->GetKeyFromPool(mapReuseKey[pfrom->addr.ip], true);
+ if (!mapReuseKey.count(pfrom->addr))
+ pwalletMain->GetKeyFromPool(mapReuseKey[pfrom->addr], true);
// Send back approval of order and pubkey to use
CScript scriptPubKey;
- scriptPubKey << mapReuseKey[pfrom->addr.ip] << OP_CHECKSIG;
+ scriptPubKey << mapReuseKey[pfrom->addr] << OP_CHECKSIG;
pfrom->PushMessage("reply", hashReply, (int)0, scriptPubKey);
}
@@ -2651,17 +2858,14 @@ bool ProcessMessages(CNode* pfrom)
}
// Checksum
- if (vRecv.GetVersion() >= 209)
+ uint256 hash = Hash(vRecv.begin(), vRecv.begin() + nMessageSize);
+ unsigned int nChecksum = 0;
+ memcpy(&nChecksum, &hash, sizeof(nChecksum));
+ if (nChecksum != hdr.nChecksum)
{
- uint256 hash = Hash(vRecv.begin(), vRecv.begin() + nMessageSize);
- unsigned int nChecksum = 0;
- memcpy(&nChecksum, &hash, sizeof(nChecksum));
- if (nChecksum != hdr.nChecksum)
- {
- printf("ProcessMessages(%s, %u bytes) : CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n",
- strCommand.c_str(), nMessageSize, nChecksum, hdr.nChecksum);
- continue;
- }
+ printf("ProcessMessages(%s, %u bytes) : CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n",
+ strCommand.c_str(), nMessageSize, nChecksum, hdr.nChecksum);
+ continue;
}
// Copy message to its own buffer
@@ -2726,18 +2930,18 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
// Address refresh broadcast
static int64 nLastRebroadcast;
- if (GetTime() - nLastRebroadcast > 24 * 60 * 60)
+ if (!IsInitialBlockDownload() && (GetTime() - nLastRebroadcast > 24 * 60 * 60))
{
- nLastRebroadcast = GetTime();
CRITICAL_BLOCK(cs_vNodes)
{
BOOST_FOREACH(CNode* pnode, vNodes)
{
// Periodically clear setAddrKnown to allow refresh broadcasts
- pnode->setAddrKnown.clear();
+ if (nLastRebroadcast)
+ pnode->setAddrKnown.clear();
// Rebroadcast our address
- if (addrLocalHost.IsRoutable() && !fUseProxy)
+ if (!fNoListen && !fUseProxy && addrLocalHost.IsRoutable())
{
CAddress addr(addrLocalHost);
addr.nTime = GetAdjustedTime();
@@ -2745,37 +2949,9 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
}
}
}
+ 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
//
@@ -2923,15 +3099,25 @@ int static FormatHashBlocks(void* pbuffer, unsigned int len)
return blocks;
}
-using CryptoPP::ByteReverse;
-
static const unsigned int pSHA256InitState[8] =
{0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
-inline void SHA256Transform(void* pstate, void* pinput, const void* pinit)
+void SHA256Transform(void* pstate, void* pinput, const void* pinit)
{
- memcpy(pstate, pinit, 32);
- CryptoPP::SHA256::Transform((CryptoPP::word32*)pstate, (CryptoPP::word32*)pinput);
+ SHA256_CTX ctx;
+ unsigned char data[64];
+
+ SHA256_Init(&ctx);
+
+ for (int i = 0; i < 16; i++)
+ ((uint32_t*)data)[i] = ByteReverse(((uint32_t*)pinput)[i]);
+
+ for (int i = 0; i < 8; i++)
+ ctx.h[i] = ((uint32_t*)pinit)[i];
+
+ SHA256_Update(&ctx, data, sizeof(data));
+ for (int i = 0; i < 8; i++)
+ ((uint32_t*)pstate)[i] = ctx.h[i];
}
//
@@ -2990,6 +3176,9 @@ public:
};
+uint64 nLastBlockTx = 0;
+uint64 nLastBlockSize = 0;
+
CBlock* CreateNewBlock(CReserveKey& reservekey)
{
CBlockIndex* pindexPrev = pindexBest;
@@ -3077,6 +3266,7 @@ CBlock* CreateNewBlock(CReserveKey& reservekey)
// Collect transactions into block
map<uint256, CTxIndex> mapTestPool;
uint64 nBlockSize = 1000;
+ uint64 nBlockTx = 0;
int nBlockSigOps = 100;
while (!mapPriority.empty())
{
@@ -3091,19 +3281,19 @@ CBlock* CreateNewBlock(CReserveKey& reservekey)
continue;
// Legacy limits on sigOps:
- int nTxSigOps = tx.GetSigOpCount();
+ int nTxSigOps = tx.GetLegacySigOpCount();
if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)
continue;
// Transaction fee required depends on block size
bool fAllowFree = (nBlockSize + nTxSize < 4000 || CTransaction::AllowFree(dPriority));
- int64 nMinFee = tx.GetMinFee(nBlockSize, fAllowFree);
+ int64 nMinFee = tx.GetMinFee(nBlockSize, fAllowFree, GMF_BLOCK);
// Connecting shouldn't fail due to dependency on other memory pool transactions
// because we're already processing them in order of dependency
map<uint256, CTxIndex> mapTestPoolTmp(mapTestPool);
- bool fInvalid;
MapPrevTx mapInputs;
+ bool fInvalid;
if (!tx.FetchInputs(txdb, mapTestPoolTmp, false, true, mapInputs, fInvalid))
continue;
@@ -3123,6 +3313,7 @@ CBlock* CreateNewBlock(CReserveKey& reservekey)
// Added
pblock->vtx.push_back(tx);
nBlockSize += nTxSize;
+ ++nBlockTx;
nBlockSigOps += nTxSigOps;
nFees += nTxFees;
@@ -3141,6 +3332,11 @@ CBlock* CreateNewBlock(CReserveKey& reservekey)
}
}
}
+
+ nLastBlockTx = nBlockTx;
+ nLastBlockSize = nBlockSize;
+ printf("CreateNewBlock(): total size %lu\n", nBlockSize);
+
}
pblock->vtx[0].vout[0].nValue = GetBlockValue(pindexPrev->nHeight+1, nFees);
@@ -3166,7 +3362,9 @@ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int&
}
++nExtraNonce;
unsigned int nHeight = pindexPrev->nHeight+1; // Height first in coinbase required for block.version=2
- pblock->vtx[0].vin[0].scriptSig = CScript() << nHeight << CBigNum(nExtraNonce);
+ pblock->vtx[0].vin[0].scriptSig = (CScript() << nHeight << CBigNum(nExtraNonce)) + COINBASE_FLAGS;
+ assert(pblock->vtx[0].vin[0].scriptSig.size() <= 100);
+
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
}
@@ -3250,12 +3448,15 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey)
return error("BitcoinMiner : ProcessBlock, block not accepted");
}
- Sleep(2000);
return true;
}
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");
@@ -3370,7 +3571,7 @@ void static BitcoinMiner(CWallet *pwallet)
{
nLogTime = GetTime();
printf("%s ", DateTimeStrFormat("%x %H:%M", GetTime()).c_str());
- printf("hashmeter %3d CPUs %6.0f khash/s\n", vnThreadsRunning[3], dHashesPerSec/1000.0);
+ printf("hashmeter %3d CPUs %6.0f khash/s\n", vnThreadsRunning[THREAD_MINER], dHashesPerSec/1000.0);
}
}
}
@@ -3381,7 +3582,7 @@ void static BitcoinMiner(CWallet *pwallet)
return;
if (!fGenerateBitcoins)
return;
- if (fLimitProcessors && vnThreadsRunning[3] > nLimitProcessors)
+ if (fLimitProcessors && vnThreadsRunning[THREAD_MINER] > nLimitProcessors)
return;
if (vNodes.empty())
break;
@@ -3410,34 +3611,34 @@ void static ThreadBitcoinMiner(void* parg)
CWallet* pwallet = (CWallet*)parg;
try
{
- vnThreadsRunning[3]++;
+ vnThreadsRunning[THREAD_MINER]++;
BitcoinMiner(pwallet);
- vnThreadsRunning[3]--;
+ vnThreadsRunning[THREAD_MINER]--;
}
catch (std::exception& e) {
- vnThreadsRunning[3]--;
+ vnThreadsRunning[THREAD_MINER]--;
PrintException(&e, "ThreadBitcoinMiner()");
} catch (...) {
- vnThreadsRunning[3]--;
+ vnThreadsRunning[THREAD_MINER]--;
PrintException(NULL, "ThreadBitcoinMiner()");
}
UIThreadCall(boost::bind(CalledSetStatusBar, "", 0));
nHPSTimerStart = 0;
- if (vnThreadsRunning[3] == 0)
+ if (vnThreadsRunning[THREAD_MINER] == 0)
dHashesPerSec = 0;
- printf("ThreadBitcoinMiner exiting, %d threads remaining\n", vnThreadsRunning[3]);
+ printf("ThreadBitcoinMiner exiting, %d threads remaining\n", vnThreadsRunning[THREAD_MINER]);
}
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);
@@ -3445,7 +3646,7 @@ void GenerateBitcoins(bool fGenerate, CWallet* pwallet)
nProcessors = 1;
if (fLimitProcessors && nProcessors > nLimitProcessors)
nProcessors = nLimitProcessors;
- int nAddThreads = nProcessors - vnThreadsRunning[3];
+ int nAddThreads = nProcessors - vnThreadsRunning[THREAD_MINER];
printf("Starting %d BitcoinMiner threads\n", nAddThreads);
for (int i = 0; i < nAddThreads; i++)
{