diff options
Diffstat (limited to 'src/main.cpp')
-rw-r--r-- | src/main.cpp | 623 |
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++) { |