@@ -735,6 +735,23 @@ double CTransaction::ComputePriority(double dPriorityInputs, unsigned int nTxSiz
735735 return dPriorityInputs / nTxSize;
736736}
737737
738+ void CTransaction::GetMapTxInputs (MapPrevTx& mapInputs) const
739+ {
740+ // Load TX inputs
741+ CTxDB txdb (" r" );
742+ map<uint256, CTxIndex> mapUnused;
743+ bool fInvalid = false ;
744+ // Ensure we can fetch inputs
745+ if (!this ->FetchInputs (txdb, mapUnused, false , false , mapInputs, fInvalid ))
746+ {
747+ if (fInvalid )
748+ {
749+ LogPrintf (" Invalid TX attempted to set in GetMapTXInputs\n " );
750+ return ;
751+ }
752+ }
753+ }
754+
738755bool CTransaction::CheckTransaction () const
739756{
740757 // Basic checks that don't depend on any context
@@ -917,7 +934,11 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CTransaction &tx, bool fLimitFree,
917934 error (" AcceptToMemoryPool : too many sigops %s, %d > %d" ,
918935 hash.ToString (), nSigOps, MAX_TX_SIGOPS));
919936
920- int64_t nFees = tx.GetValueIn (mapInputs)-tx.GetValueOut ();
937+ int64_t nFees = tx.GetValueMapIn (mapInputs)-tx.GetValueOut ();
938+ if (tx.GetValueMapIn (mapInputs) < tx.GetValueOut ()) {
939+ LogPrintf (" AcceptToMemoryPool : tx input is less that output\n " );
940+ return tx.DoS (100 , error (" AcceptToMemoryPool : tx input is less that output" ));
941+ }
921942 unsigned int nSize = ::GetSerializeSize (tx, SER_NETWORK, PROTOCOL_VERSION);
922943
923944 // Don't accept it if it can't get into a block
@@ -1079,7 +1100,11 @@ bool AcceptableInputs(CTxMemPool& pool, const CTransaction &txo, bool fLimitFree
10791100 error (" AcceptableInputs : too many sigops %s, %d > %d" ,
10801101 hash.ToString (), nSigOps, MAX_TX_SIGOPS));
10811102
1082- int64_t nFees = tx.GetValueIn (mapInputs)-tx.GetValueOut ();
1103+ int64_t nFees = tx.GetValueMapIn (mapInputs)-tx.GetValueOut ();
1104+ if (tx.GetValueMapIn (mapInputs) < tx.GetValueOut ()) {
1105+ LogPrintf (" AcceptableInputs : tx input is less that output\n " );
1106+ return error (" AcceptableInputs : tx input is less than output" );
1107+ }
10831108 unsigned int nSize = ::GetSerializeSize (tx, SER_NETWORK, PROTOCOL_VERSION);
10841109 int64_t txMinFee = GetMinFee (tx, nSize, true , GMF_RELAY);
10851110
@@ -1568,7 +1593,7 @@ bool CTransaction::DisconnectInputs(CTxDB& txdb)
15681593
15691594
15701595bool CTransaction::FetchInputs (CTxDB& txdb, const map<uint256, CTxIndex>& mapTestPool,
1571- bool fBlock , bool fMiner , MapPrevTx& inputsRet, bool & fInvalid )
1596+ bool fBlock , bool fMiner , MapPrevTx& inputsRet, bool & fInvalid ) const
15721597{
15731598 // FetchInputs can return false either because we just haven't seen some inputs
15741599 // (in which case the transaction should be stored as an orphan)
@@ -1651,7 +1676,7 @@ const CTxOut& CTransaction::GetOutputFor(const CTxIn& input, const MapPrevTx& in
16511676 return txPrev.vout [input.prevout .n ];
16521677}
16531678
1654- int64_t CTransaction::GetValueIn (const MapPrevTx& inputs) const
1679+ int64_t CTransaction::GetValueMapIn (const MapPrevTx& inputs) const
16551680{
16561681 if (IsCoinBase ())
16571682 return 0 ;
@@ -1972,12 +1997,17 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck)
19721997 if (nSigOps > MAX_BLOCK_SIGOPS)
19731998 return DoS (100 , error (" ConnectBlock() : too many sigops" ));
19741999
1975- int64_t nTxValueIn = tx.GetValueIn (mapInputs);
2000+ int64_t nTxValueIn = tx.GetValueMapIn (mapInputs);
19762001 int64_t nTxValueOut = tx.GetValueOut ();
19772002 nValueIn += nTxValueIn;
19782003 nValueOut += nTxValueOut;
1979- if (!tx.IsCoinStake ())
2004+ if (!tx.IsCoinStake ()) {
19802005 nFees += nTxValueIn - nTxValueOut;
2006+ if (nTxValueIn < nTxValueOut) {
2007+ LogPrintf (" ConnectBlock : block contains a tx input that is less that output\n " );
2008+ return false ;
2009+ }
2010+ }
19812011 if (tx.IsCoinStake ())
19822012 nStakeReward = nTxValueOut - nTxValueIn;
19832013
@@ -2912,10 +2942,28 @@ bool CBlock::AcceptBlock()
29122942 if (GetBlockTime () <= pindexPrev->GetPastTimeLimit () || FutureDrift (GetBlockTime ()) < pindexPrev->GetBlockTime ())
29132943 return error (" AcceptBlock() : block's timestamp is too early" );
29142944
2945+ // Set logged values
2946+ CAmount tx_inputs_values = 0 ;
2947+ CAmount tx_outputs_values = 0 ;
2948+ CAmount tx_threshold = (300 * COIN);
29152949 // Check that all transactions are finalized
29162950 BOOST_FOREACH (const CTransaction& tx, vtx)
2917- if (!IsFinalTx (tx, nHeight, GetBlockTime ()))
2951+ {
2952+ if (!IsFinalTx (tx, nHeight, GetBlockTime ())) {
29182953 return DoS (10 , error (" AcceptBlock() : contains a non-final transaction" ));
2954+ }
2955+ // Log inputs/output values
2956+ MapPrevTx mapInputs;
2957+ tx.GetMapTxInputs (mapInputs);
2958+ tx_inputs_values += tx.GetValueMapIn (mapInputs);
2959+ tx_outputs_values += tx.GetValueOut ();
2960+ }
2961+
2962+ // Ensure input/output sanity of transactions in the block
2963+ if ((tx_inputs_values + tx_threshold) < tx_outputs_values)
2964+ {
2965+ return DoS (100 , error (" AcceptBlock() : block contains a tx input that is less that output" ));
2966+ }
29192967
29202968 // Check that the block chain matches the known block chain up to a checkpoint
29212969 if (!Checkpoints::CheckHardened (nHeight, hash))
0 commit comments