aboutsummaryrefslogtreecommitdiff
path: root/src/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.cpp')
-rw-r--r--src/main.cpp74
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;