diff options
Diffstat (limited to 'src/main.cpp')
-rw-r--r-- | src/main.cpp | 74 |
1 files changed, 49 insertions, 25 deletions
diff --git a/src/main.cpp b/src/main.cpp index 847b1ea8a6..8c115c26f9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -362,6 +362,14 @@ bool CTransaction::IsStandard() const if (!IsFinal()) return false; + // Extremely large transactions with lots of inputs can cost the network + // almost as much to process as they cost the sender in fees, because + // computing signature hashes is O(ninputs*txsize). Limiting transactions + // to MAX_STANDARD_TX_SIZE mitigates CPU exhaustion attacks. + unsigned int sz = this->GetSerializeSize(SER_NETWORK, CTransaction::CURRENT_VERSION); + if (sz >= MAX_STANDARD_TX_SIZE) + return false; + BOOST_FOREACH(const CTxIn& txin, vin) { // Biggest 'standard' txin is a 3-signature 3-of-3 CHECKMULTISIG @@ -1250,7 +1258,6 @@ bool ConnectBestBlock(CValidationState &state) { BOOST_FOREACH(CBlockIndex *pindexSwitch, vAttach) { if (fRequestShutdown) break; - CValidationState state; try { if (!SetBestChain(state, pindexSwitch)) return false; @@ -1405,7 +1412,7 @@ bool CTransaction::CheckInputs(CValidationState &state, CCoinsViewCache &inputs, } if (nValueIn < GetValueOut()) - return state.DoS(100, error("ChecktInputs() : %s value in < value out", GetHash().ToString().substr(0,10).c_str())); + return state.DoS(100, error("CheckInputs() : %s value in < value out", GetHash().ToString().substr(0,10).c_str())); // Tally transaction fees int64 nTxFee = nValueIn - GetValueOut(); @@ -1598,7 +1605,7 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi for (unsigned int i=0; i<vtx.size(); i++) { uint256 hash = GetTxHash(i); if (view.HaveCoins(hash) && !view.GetCoins(hash).IsPruned()) - return error("ConnectBlock() : tried to overwrite transaction"); + return state.DoS(100, error("ConnectBlock() : tried to overwrite transaction")); } } @@ -2259,7 +2266,9 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl ++mi) { CBlock* pblockOrphan = (*mi).second; - if (pblockOrphan->AcceptBlock(state)) + // Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan resolution (that is, feeding people an invalid block based on LegitBlockX in order to get anyone relaying LegitBlockX banned) + CValidationState stateDummy; + if (pblockOrphan->AcceptBlock(stateDummy)) vWorkQueue.push_back(pblockOrphan->GetHash()); mapOrphanBlocks.erase(pblockOrphan->GetHash()); delete pblockOrphan; @@ -2661,18 +2670,22 @@ bool LoadBlockIndex() if (!fReindex && !LoadBlockIndexDB()) return false; - // - // Init with genesis block - // - if (mapBlockIndex.empty()) - { - fTxIndex = GetBoolArg("-txindex", false); - pblocktree->WriteFlag("txindex", fTxIndex); - printf("Initializing databases...\n"); + return true; +} - if (fReindex) - return true; +bool InitBlockIndex() { + // Check whether we're already initialized + if (pindexGenesisBlock != NULL) + return true; + + // Use the provided setting for -txindex in the new database + fTxIndex = GetBoolArg("-txindex", false); + pblocktree->WriteFlag("txindex", fTxIndex); + printf("Initializing databases...\n"); + + // Only add the genesis block if not reindexing (in which case we reuse the one already on disk) + if (!fReindex) { // Genesis Block: // CBlock(hash=000000000019d6, ver=1, hashPrevBlock=00000000000000, hashMerkleRoot=4a5e1e, nTime=1231006505, nBits=1d00ffff, nNonce=2083236893, vtx=1) // CTransaction(hash=4a5e1e, ver=1, vin.size=1, vout.size=1, nLockTime=0) @@ -2713,15 +2726,19 @@ bool LoadBlockIndex() assert(hash == hashGenesisBlock); // Start new block file - unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION); - CDiskBlockPos blockPos; - CValidationState state; - if (!FindBlockPos(state, blockPos, nBlockSize+8, 0, block.nTime)) - return error("AcceptBlock() : FindBlockPos failed"); - if (!block.WriteToDisk(blockPos)) - return error("LoadBlockIndex() : writing genesis block to disk failed"); - if (!block.AddToBlockIndex(state, blockPos)) - return error("LoadBlockIndex() : genesis block not accepted"); + try { + unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION); + CDiskBlockPos blockPos; + CValidationState state; + if (!FindBlockPos(state, blockPos, nBlockSize+8, 0, block.nTime)) + return error("AcceptBlock() : FindBlockPos failed"); + if (!block.WriteToDisk(blockPos)) + return error("LoadBlockIndex() : writing genesis block to disk failed"); + if (!block.AddToBlockIndex(state, blockPos)) + return error("LoadBlockIndex() : genesis block not accepted"); + } catch(std::runtime_error &e) { + return error("LoadBlockIndex() : failed to initialize block database: %s", e.what()); + } } return true; @@ -3453,8 +3470,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) CDataStream(vMsg) >> tx; CInv inv(MSG_TX, tx.GetHash()); bool fMissingInputs2 = false; + // Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan resolution (that is, feeding people an invalid transaction based on LegitTxX in order to get anyone relaying LegitTxX banned) + CValidationState stateDummy; - if (tx.AcceptToMemoryPool(state, true, true, &fMissingInputs2)) + if (tx.AcceptToMemoryPool(stateDummy, true, true, &fMissingInputs2)) { printf(" accepted orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str()); RelayTransaction(tx, inv.hash, vMsg); @@ -3793,7 +3812,12 @@ bool SendMessages(CNode* pto, bool fSendTrickle) } // Resend wallet transactions that haven't gotten in a block yet - ResendWalletTransactions(); + // Except during reindex, importing and IBD, when old wallet + // transactions become unconfirmed and spams other nodes. + if (!fReindex && !fImporting && !IsInitialBlockDownload()) + { + ResendWalletTransactions(); + } // Address refresh broadcast static int64 nLastRebroadcast; |