@@ -275,26 +275,22 @@ bool CTransaction::IsStandard() const
275275// expensive-to-check-upon-redemption script like:
276276// DUP CHECKSIG DROP ... repeated 100 times... OP_1
277277//
278- bool CTransaction::AreInputsStandard (const std::map<uint256, std::pair<CTxIndex, CTransaction> > & mapInputs) const
278+ bool CTransaction::AreInputsStandard (const MapPrevTx & mapInputs) const
279279{
280280 if (fTestNet )
281281 return true ; // Allow non-standard on testnet
282282
283+ if (IsCoinBase ())
284+ return true ; // Coinbases are allowed to have any input
285+
283286 for (int i = 0 ; i < vin.size (); i++)
284287 {
285- COutPoint prevout = vin[i].prevout ;
286-
287- std::map<uint256, std::pair<CTxIndex, CTransaction> >::const_iterator mi = mapInputs.find (prevout.hash );
288- if (mi == mapInputs.end ())
289- return false ;
290-
291- const CTransaction& txPrev = (mi->second ).second ;
292- assert (prevout.n < txPrev.vout .size ());
288+ const CTxOut& prev = GetOutputFor (vin[i], mapInputs);
293289
294290 vector<vector<unsigned char > > vSolutions;
295291 txnouttype whichType;
296292 // get the scriptPubKey corresponding to this input:
297- const CScript& prevScript = txPrev. vout [prevout. n ] .scriptPubKey ;
293+ const CScript& prevScript = prev .scriptPubKey ;
298294 if (!Solver (prevScript, whichType, vSolutions))
299295 return false ;
300296 if (whichType == TX_SCRIPTHASH)
@@ -494,7 +490,7 @@ bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMi
494490
495491 if (fCheckInputs )
496492 {
497- map<uint256, pair<CTxIndex, CTransaction> > mapInputs;
493+ MapPrevTx mapInputs;
498494 map<uint256, CTxIndex> mapUnused;
499495 if (!FetchInputs (txdb, mapUnused, false , false , mapInputs))
500496 {
@@ -507,27 +503,20 @@ bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMi
507503 if (!AreInputsStandard (mapInputs))
508504 return error (" AcceptToMemoryPool() : nonstandard transaction input" );
509505
510- // Check against previous transactions
511- int64 nFees = 0 ;
512- int nSigOps = 0 ;
513- if (!ConnectInputs (mapInputs, mapUnused, CDiskTxPos (1 ,1 ,1 ), pindexBest, nFees, false , false , nSigOps))
514- {
515- if (pfMissingInputs)
516- *pfMissingInputs = true ;
517- return error (" AcceptToMemoryPool() : ConnectInputs failed %s" , hash.ToString ().substr (0 ,10 ).c_str ());
518- }
506+ int64 nFees = GetValueIn (mapInputs)-GetValueOut ();
507+ int nSigOps = GetSigOpCount (mapInputs);
508+ unsigned int nSize = ::GetSerializeSize (*this , SER_NETWORK);
509+
510+ // Don't accept it if it can't get into a block
511+ if (nFees < GetMinFee (1000 , true , GMF_RELAY))
512+ return error (" AcceptToMemoryPool() : not enough fees" );
519513
520514 // Checking ECDSA signatures is a CPU bottleneck, so to avoid denial-of-service
521515 // attacks disallow transactions with more than one SigOp per 65 bytes.
522516 // 65 bytes because that is the minimum size of an ECDSA signature
523- unsigned int nSize = ::GetSerializeSize (*this , SER_NETWORK);
524517 if (nSigOps > nSize / 65 || nSize < 100 )
525518 return error (" AcceptToMemoryPool() : transaction with out-of-bounds SigOpCount" );
526519
527- // Don't accept it if it can't get into a block
528- if (nFees < GetMinFee (1000 , true , GMF_RELAY))
529- return error (" AcceptToMemoryPool() : not enough fees" );
530-
531520 // Continuously rate-limit free transactions
532521 // This mitigates 'penny-flooding' -- sending thousands of free transactions just to
533522 // be annoying or make other's transactions take longer to confirm.
@@ -552,6 +541,15 @@ bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMi
552541 dFreeCount += nSize;
553542 }
554543 }
544+
545+ // Check against previous transactions
546+ // This is done last to help prevent CPU exhaustion denial-of-service attacks.
547+ if (!ConnectInputs (mapInputs, mapUnused, CDiskTxPos (1 ,1 ,1 ), pindexBest, false , false ))
548+ {
549+ if (pfMissingInputs)
550+ *pfMissingInputs = true ;
551+ return error (" AcceptToMemoryPool() : ConnectInputs failed %s" , hash.ToString ().substr (0 ,10 ).c_str ());
552+ }
555553 }
556554
557555 // Store transaction in memory
@@ -925,7 +923,7 @@ bool CTransaction::DisconnectInputs(CTxDB& txdb)
925923
926924
927925bool CTransaction::FetchInputs (CTxDB& txdb, const map<uint256, CTxIndex>& mapTestPool,
928- bool fBlock , bool fMiner , map<uint256, pair<CTxIndex, CTransaction> > & inputsRet)
926+ bool fBlock , bool fMiner , MapPrevTx & inputsRet)
929927{
930928 if (IsCoinBase ())
931929 return true ; // Coinbase transactions have no inputs to fetch.
@@ -978,6 +976,7 @@ bool CTransaction::FetchInputs(CTxDB& txdb, const map<uint256, CTxIndex>& mapTes
978976 for (int i = 0 ; i < vin.size (); i++)
979977 {
980978 const COutPoint prevout = vin[i].prevout ;
979+ assert (inputsRet.count (prevout.hash ) != 0 );
981980 const CTxIndex& txindex = inputsRet[prevout.hash ].first ;
982981 const CTransaction& txPrev = inputsRet[prevout.hash ].second ;
983982 if (prevout.n >= txPrev.vout .size () || prevout.n >= txindex.vSpent .size ())
@@ -987,9 +986,49 @@ bool CTransaction::FetchInputs(CTxDB& txdb, const map<uint256, CTxIndex>& mapTes
987986 return true ;
988987}
989988
990- bool CTransaction::ConnectInputs (map<uint256, pair<CTxIndex, CTransaction> > inputs,
989+ const CTxOut& CTransaction::GetOutputFor (const CTxIn& input, const MapPrevTx& inputs) const
990+ {
991+ MapPrevTx::const_iterator mi = inputs.find (input.prevout .hash );
992+ if (mi == inputs.end ())
993+ throw std::runtime_error (" CTransaction::GetOutputFor() : prevout.hash not found" );
994+
995+ const CTransaction& txPrev = (mi->second ).second ;
996+ if (input.prevout .n >= txPrev.vout .size ())
997+ throw std::runtime_error (" CTransaction::GetOutputFor() : prevout.n out of range" );
998+
999+ return txPrev.vout [input.prevout .n ];
1000+ }
1001+
1002+ int64 CTransaction::GetValueIn (const MapPrevTx& inputs) const
1003+ {
1004+ if (IsCoinBase ())
1005+ return 0 ;
1006+
1007+ int64 nResult = 0 ;
1008+ for (int i = 0 ; i < vin.size (); i++)
1009+ {
1010+ nResult += GetOutputFor (vin[i], inputs).nValue ;
1011+ }
1012+ return nResult;
1013+
1014+ }
1015+
1016+ int CTransaction::GetSigOpCount (const MapPrevTx& inputs) const
1017+ {
1018+ if (IsCoinBase ())
1019+ return 0 ;
1020+
1021+ int nSigOps = 0 ;
1022+ for (int i = 0 ; i < vin.size (); i++)
1023+ {
1024+ nSigOps += GetOutputFor (vin[i], inputs).scriptPubKey .GetSigOpCount (vin[i].scriptSig );
1025+ }
1026+ return nSigOps;
1027+ }
1028+
1029+ bool CTransaction::ConnectInputs (MapPrevTx inputs,
9911030 map<uint256, CTxIndex>& mapTestPool, const CDiskTxPos& posThisTx,
992- const CBlockIndex* pindexBlock, int64& nFees, bool fBlock , bool fMiner , int & nSigOpsRet, int64 nMinFee )
1031+ const CBlockIndex* pindexBlock, bool fBlock , bool fMiner )
9931032{
9941033 // Take over previous transactions' spent pointers
9951034 // fBlock is true when this is called from AcceptBlock when a new best-block is added to the blockchain
@@ -998,6 +1037,7 @@ bool CTransaction::ConnectInputs(map<uint256, pair<CTxIndex, CTransaction> > inp
9981037 if (!IsCoinBase ())
9991038 {
10001039 int64 nValueIn = 0 ;
1040+ int64 nFees = 0 ;
10011041 for (int i = 0 ; i < vin.size (); i++)
10021042 {
10031043 COutPoint prevout = vin[i].prevout ;
@@ -1014,6 +1054,17 @@ bool CTransaction::ConnectInputs(map<uint256, pair<CTxIndex, CTransaction> > inp
10141054 if (pindex->nBlockPos == txindex.pos .nBlockPos && pindex->nFile == txindex.pos .nFile )
10151055 return error (" ConnectInputs() : tried to spend coinbase at depth %d" , pindexBlock->nHeight - pindex->nHeight );
10161056
1057+ // Check for conflicts (double-spend)
1058+ // This doesn't trigger the DoS code on purpose; if it did, it would make it easier
1059+ // for an attacker to attempt to split the network.
1060+ if (!txindex.vSpent [prevout.n ].IsNull ())
1061+ 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 ());
1062+
1063+ // Check for negative or overflow input values
1064+ nValueIn += txPrev.vout [prevout.n ].nValue ;
1065+ if (!MoneyRange (txPrev.vout [prevout.n ].nValue ) || !MoneyRange (nValueIn))
1066+ return DoS (100 , error (" ConnectInputs() : txin values out of range" ));
1067+
10171068 bool fStrictPayToScriptHash = true ;
10181069 if (fBlock )
10191070 {
@@ -1038,20 +1089,6 @@ bool CTransaction::ConnectInputs(map<uint256, pair<CTxIndex, CTransaction> > inp
10381089 return DoS (100 ,error (" ConnectInputs() : %s VerifySignature failed" , GetHash ().ToString ().substr (0 ,10 ).c_str ()));
10391090 }
10401091
1041- // Check for conflicts (double-spend)
1042- // This doesn't trigger the DoS code on purpose; if it did, it would make it easier
1043- // for an attacker to attempt to split the network.
1044- if (!txindex.vSpent [prevout.n ].IsNull ())
1045- 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 ());
1046-
1047- // Check for negative or overflow input values
1048- nValueIn += txPrev.vout [prevout.n ].nValue ;
1049- if (!MoneyRange (txPrev.vout [prevout.n ].nValue ) || !MoneyRange (nValueIn))
1050- return DoS (100 , error (" ConnectInputs() : txin values out of range" ));
1051-
1052- // Calculate sigOps accurately:
1053- nSigOpsRet += txPrev.vout [prevout.n ].scriptPubKey .GetSigOpCount (vin[i].scriptSig );
1054-
10551092 // Mark outpoints as spent
10561093 txindex.vSpent [prevout.n ] = posThisTx;
10571094
@@ -1069,8 +1106,6 @@ bool CTransaction::ConnectInputs(map<uint256, pair<CTxIndex, CTransaction> > inp
10691106 int64 nTxFee = nValueIn - GetValueOut ();
10701107 if (nTxFee < 0 )
10711108 return DoS (100 , error (" ConnectInputs() : %s nTxFee < 0" , GetHash ().ToString ().substr (0 ,10 ).c_str ()));
1072- if (nTxFee < nMinFee)
1073- return false ;
10741109 nFees += nTxFee;
10751110 if (!MoneyRange (nFees))
10761111 return DoS (100 , error (" ConnectInputs() : nFees out of range" ));
@@ -1176,20 +1211,27 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex)
11761211 CDiskTxPos posThisTx (pindex->nFile , pindex->nBlockPos , nTxPos);
11771212 nTxPos += ::GetSerializeSize (tx, SER_DISK);
11781213
1179- map<uint256, pair<CTxIndex, CTransaction> > mapInputs;
1180- if (!tx.FetchInputs (txdb, mapQueuedChanges, true , false , mapInputs))
1181- return false ;
1214+ MapPrevTx mapInputs;
1215+ if (!tx.IsCoinBase ())
1216+ {
1217+ if (!tx.FetchInputs (txdb, mapQueuedChanges, true , false , mapInputs))
1218+ return false ;
11821219
1183- int nTxOps = 0 ;
1184- if (!tx.ConnectInputs (mapInputs, mapQueuedChanges, posThisTx, pindex, nFees, true , false , nTxOps))
1185- return false ;
1220+ int nTxOps = tx.GetSigOpCount (mapInputs);
1221+ nSigOps += nTxOps;
1222+ if (nSigOps > MAX_BLOCK_SIGOPS)
1223+ return DoS (100 , error (" ConnectBlock() : too many sigops" ));
1224+ // There is a different MAX_BLOCK_SIGOPS check in AcceptBlock();
1225+ // a block must satisfy both to make it into the best-chain
1226+ // (AcceptBlock() is always called before ConnectBlock())
11861227
1187- nSigOps += nTxOps;
1188- if (nSigOps > MAX_BLOCK_SIGOPS)
1189- return DoS (100 , error (" ConnectBlock() : too many sigops" ));
1190- // There is a different MAX_BLOCK_SIGOPS check in AcceptBlock();
1191- // a block must satisfy both to make it into the best-chain
1192- // (AcceptBlock() is always called before ConnectBlock())
1228+ nFees += tx.GetValueIn (mapInputs)-tx.GetValueOut ();
1229+ }
1230+
1231+ // It seems wrong that ConnectInputs must be called on the coinbase transaction
1232+ // (which has no inputs) : TODO: refactor the code at the end of ConnectInputs out...
1233+ if (!tx.ConnectInputs (mapInputs, mapQueuedChanges, posThisTx, pindex, true , false ))
1234+ return false ;
11931235 }
11941236
11951237 // Write queued txindex changes
@@ -3031,15 +3073,20 @@ CBlock* CreateNewBlock(CReserveKey& reservekey)
30313073 // Connecting shouldn't fail due to dependency on other memory pool transactions
30323074 // because we're already processing them in order of dependency
30333075 map<uint256, CTxIndex> mapTestPoolTmp (mapTestPool);
3034- map<uint256, pair<CTxIndex, CTransaction> > mapInputs;
3076+ MapPrevTx mapInputs;
30353077 if (!tx.FetchInputs (txdb, mapTestPoolTmp, false , true , mapInputs))
30363078 continue ;
30373079
3038- int nTxSigOps2 = 0 ;
3039- if (!tx. ConnectInputs (mapInputs, mapTestPoolTmp, CDiskTxPos ( 1 , 1 , 1 ), pindexPrev, nFees, false , true , nTxSigOps2, nMinFee) )
3080+ int64 nFees = tx. GetValueIn (mapInputs)-tx. GetValueOut () ;
3081+ if (nFees < nMinFee)
30403082 continue ;
3083+
3084+ int nTxSigOps2 = tx.GetSigOpCount (mapInputs);
30413085 if (nBlockSigOps2 + nTxSigOps2 >= MAX_BLOCK_SIGOPS)
30423086 continue ;
3087+
3088+ if (!tx.ConnectInputs (mapInputs, mapTestPoolTmp, CDiskTxPos (1 ,1 ,1 ), pindexPrev, false , true ))
3089+ continue ;
30433090 swap (mapTestPool, mapTestPoolTmp);
30443091
30453092 // Added
0 commit comments