diff --git a/src/coins.cpp b/src/coins.cpp index bca1ebb9f5..9a6cb9ae43 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -257,11 +257,37 @@ CAmount CCoinsViewCache::GetValueIn(const CTransaction& tx) const CAmount nResult = 0; for (unsigned int i = 0; i < tx.vin.size(); i++) - nResult += GetOutputFor(tx.vin[i]).nValue; + { + const CTxOutValue& val = GetOutputFor(tx.vin[i]).nValue; + assert(val.IsAmount()); + nResult += val.GetAmount(); + } return nResult; } +CAmount CCoinsViewCache::GetValueInExcess(const CTransaction& tx) const +{ + const CAmount nValueIn = GetValueIn(tx); + const CAmount nValueOut = tx.GetValueOut(); + return nValueIn - nValueOut; +} + +bool CCoinsViewCache::VerifyAmounts(const CTransaction& tx, const CAmount& excess) const +{ + CAmount nInAmount = GetValueIn(tx); + if (nInAmount < excess) + return false; + nInAmount -= excess; + return nInAmount == tx.GetValueOut(); +} + +bool CCoinsViewCache::VerifyAmounts(const CTransaction& tx) const +{ + const CAmount excess = GetValueInExcess(tx); + return VerifyAmounts(tx, excess); +} + bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const { if (!tx.IsCoinBase()) { @@ -294,8 +320,13 @@ double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight) const // Coins moving to this chain get a priority bump nOffset = 100; int nCoinsHeight = coins->nHeight == 0x7fffffff ? nHeight + 1 : coins->nHeight; - if (nCoinsHeight < nHeight + nOffset) - dResult += (coins->vout[txin.prevout.n].nValue + nOffset) * (nHeight - nCoinsHeight + nOffset); + if (nCoinsHeight < nHeight + nOffset) { + const CTxOutValue& val = coins->vout[txin.prevout.n].nValue; + CAmount nAmount = COIN; + if (val.IsAmount()) + nAmount = val.GetAmount(); + dResult += (nAmount + nOffset) * (nHeight - nCoinsHeight + nOffset); + } } return tx.ComputePriority(dResult); } diff --git a/src/coins.h b/src/coins.h index ad96226ed6..9299458478 100644 --- a/src/coins.h +++ b/src/coins.h @@ -304,9 +304,8 @@ struct CCoinsStats uint64_t nTransactionOutputs; uint64_t nSerializedSize; uint256 hashSerialized; - CAmount nTotalAmount; - CCoinsStats() : nHeight(0), hashBlock(0), nTransactions(0), nTransactionOutputs(0), nSerializedSize(0), hashSerialized(0), nTotalAmount(0) {} + CCoinsStats() : nHeight(0), hashBlock(0), nTransactions(0), nTransactionOutputs(0), nSerializedSize(0), hashSerialized(0) {} }; @@ -440,6 +439,18 @@ public: */ CAmount GetValueIn(const CTransaction& tx) const; + CAmount GetValueInExcess(const CTransaction& tx) const; + + /** + * Verify the transaction's outputs spend exactly what its inputs provide, plus some excess amount. + * + * @param[in] tx transaction for which we are checking totals + * @param[in] excess additional amount to consider (eg, fees) + * @return True if totals are identical + */ + bool VerifyAmounts(const CTransaction& tx, const CAmount& excess) const; + bool VerifyAmounts(const CTransaction& tx) const; + //! Check whether all prevouts of the transaction are present in the UTXO set represented by this view bool HaveInputs(const CTransaction& tx) const; diff --git a/src/compressor.h b/src/compressor.h index efb8119d01..a2839e3f35 100644 --- a/src/compressor.h +++ b/src/compressor.h @@ -108,7 +108,8 @@ public: template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { if (!ser_action.ForRead()) { - uint64_t nVal = CompressAmount(txout.nValue); + assert(txout.nValue.IsAmount()); // FIXME + uint64_t nVal = CompressAmount(txout.nValue.GetAmount()); READWRITE(VARINT(nVal)); } else { uint64_t nVal = 0; diff --git a/src/core_write.cpp b/src/core_write.cpp index c40c8962f3..d644f8a611 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -123,8 +123,11 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry) UniValue out(UniValue::VOBJ); - UniValue outValue(UniValue::VNUM, FormatMoney(txout.nValue)); - out.pushKV("value", outValue); + if (txout.nValue.IsAmount()) + { + UniValue outValue(UniValue::VNUM, FormatMoney(txout.nValue.GetAmount())); + out.pushKV("value", outValue); + } out.pushKV("n", (int64_t)i); UniValue o(UniValue::VOBJ); diff --git a/src/main.cpp b/src/main.cpp index 27f59ec500..fa979a6a06 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -946,13 +946,20 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state) CAmount nValueOut = 0; BOOST_FOREACH(const CTxOut& txout, tx.vout) { - if (txout.nValue < 0) + if (!txout.nValue.IsValid()) + return state.DoS(100, error("CheckTransaction() : txout.nValue invalid"), + REJECT_INVALID, "bad-txns-vout-amount-invalid"); + if (!txout.nValue.IsAmount()) + continue; + + const CAmount nOutAmount = txout.nValue.GetAmount(); + if (nOutAmount < 0) return state.DoS(100, error("CheckTransaction() : txout.nValue negative"), REJECT_INVALID, "bad-txns-vout-negative"); - if (txout.nValue > MAX_MONEY) + if (nOutAmount > MAX_MONEY) return state.DoS(100, error("CheckTransaction() : txout.nValue too high"), REJECT_INVALID, "bad-txns-vout-toolarge"); - nValueOut += txout.nValue; + nValueOut += nOutAmount; if (!MoneyRange(nValueOut)) return state.DoS(100, error("CheckTransaction() : txout total out of range"), REJECT_INVALID, "bad-txns-txouttotal-toolarge"); @@ -1060,7 +1067,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa CCoinsView dummy; CCoinsViewCache view(&dummy); - CAmount nValueIn = 0; + CAmount nFees = 0; { LOCK(pool.cs); CCoinsViewMemPool viewMemPool(pcoinsTip, pool); @@ -1089,7 +1096,12 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // Bring the best block into scope view.GetBestBlock(); - nValueIn = view.GetValueIn(tx); + nFees = view.GetValueInExcess(tx); + if (!view.VerifyAmounts(tx, nFees)) + return state.DoS(0, + error("AcceptToMemoryPool : input amounts do not match output amounts %s", + hash.ToString()), + REJECT_NONSTANDARD, "bad-txns-amount-mismatch"); // we have all inputs cached now, so switch back to dummy, so we don't need to keep lock on mempool view.SetBackend(dummy); @@ -1127,8 +1139,6 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa hash.ToString(), nSigOps, MAX_TX_SIGOPS), REJECT_NONSTANDARD, "bad-txns-too-many-sigops"); - CAmount nValueOut = tx.GetValueOut(); - CAmount nFees = nValueIn-nValueOut; double dPriority = view.GetPriority(tx, chainActive.Height()); CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height()); @@ -1551,8 +1561,6 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi // This is also true for mempool checks. CBlockIndex *pindexPrev = mapBlockIndex.find(inputs.GetBestBlock())->second; int nSpendHeight = pindexPrev->nHeight + 1; - CAmount nValueIn = 0; - CAmount nFees = 0; for (unsigned int i = 0; i < tx.vin.size(); i++) { const COutPoint &prevout = tx.vin[i].prevout; @@ -1566,30 +1574,22 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi error("CheckInputs() : tried to spend coinbase at depth %d", nSpendHeight - coins->nHeight), REJECT_INVALID, "bad-txns-premature-spend-of-coinbase"); } - - // Check for negative or overflow input values - nValueIn += coins->vout[prevout.n].nValue; - if (!MoneyRange(coins->vout[prevout.n].nValue) || !MoneyRange(nValueIn)) - return state.DoS(100, error("CheckInputs() : txin values out of range"), - REJECT_INVALID, "bad-txns-inputvalues-outofrange"); - } - if (nValueIn < tx.GetValueOut()) - return state.DoS(100, error("CheckInputs() : %s value in (%s) < value out (%s)", - tx.GetHash().ToString(), FormatMoney(nValueIn), FormatMoney(tx.GetValueOut())), - REJECT_INVALID, "bad-txns-in-belowout"); - - // Tally transaction fees - CAmount nTxFee = nValueIn - tx.GetValueOut(); + const CAmount nTxFee = inputs.GetValueInExcess(tx); if (nTxFee < 0) return state.DoS(100, error("CheckInputs() : %s nTxFee < 0", tx.GetHash().ToString()), REJECT_INVALID, "bad-txns-fee-negative"); - nFees += nTxFee; - if (!MoneyRange(nFees)) - return state.DoS(100, error("CheckInputs() : nFees out of range"), + + if (!MoneyRange(nTxFee)) + return state.DoS(100, error("CheckInputs() : nTxFee out of range"), REJECT_INVALID, "bad-txns-fee-outofrange"); + if (!inputs.VerifyAmounts(tx, nTxFee)) + return state.DoS(100, error("CheckInputs() : %s value in != value out", + tx.GetHash().ToString()), + REJECT_INVALID, "bad-txns-amount-mismatch"); + // The first loop above does all the inexpensive checks. // Only if ALL inputs pass do we perform expensive ECDSA signature checks. // Helps prevent CPU exhaustion attacks. @@ -1880,7 +1880,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin REJECT_INVALID, "bad-blk-sigops"); } - nFees += view.GetValueIn(tx)-tx.GetValueOut(); + nFees += view.GetValueInExcess(tx); std::vector vChecks; if (!CheckInputs(tx, state, view, fScriptChecks, flags, false, nScriptCheckThreads ? &vChecks : NULL)) @@ -2000,10 +2000,10 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin int64_t nTime1 = GetTimeMicros(); nTimeConnect += nTime1 - nTimeStart; LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\n", (unsigned)block.vtx.size(), 0.001 * (nTime1 - nTimeStart), 0.001 * (nTime1 - nTimeStart) / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * (nTime1 - nTimeStart) / (nInputs-1), nTimeConnect * 0.000001); - if (block.vtx[0].GetValueOut() > GetBlockValue(pindex->nHeight, nFees)) + if (!view.VerifyAmounts(block.vtx[0], -GetBlockValue(pindex->nHeight, nFees))) return state.DoS(100, - error("ConnectBlock() : coinbase pays too much (actual=%d vs limit=%d)", - block.vtx[0].GetValueOut(), GetBlockValue(pindex->nHeight, nFees)), + error("ConnectBlock() : coinbase pays too much (actual=UNKNOWN vs limit=%d)", + GetBlockValue(pindex->nHeight, nFees)), REJECT_INVALID, "bad-cb-amount"); if (!control.Wait()) diff --git a/src/miner.cpp b/src/miner.cpp index 5b9c7e2a0c..4b3409e415 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -42,10 +42,10 @@ class COrphan public: const CTransaction* ptx; set setDependsOn; - CFeeRate feeRate; - double dPriority; + unsigned int nTxSize; + double dPriorityBeforeDelta; - COrphan(const CTransaction* ptxIn) : ptx(ptxIn), feeRate(0), dPriority(0) + COrphan(const CTransaction* ptxIn) : ptx(ptxIn), nTxSize(0), dPriorityBeforeDelta(0) { } }; @@ -94,6 +94,14 @@ int64_t UpdateTime(CBlockHeader* pblock, const CBlockIndex* pindexPrev) return nNewTime - nOldTime; } +static CFeeRate CalculateSubjectiveFeeRateAndPriority(const CCoinsViewCache& view, const CTransaction& tx, const unsigned int& nTxSize, double& dPriority) { + const uint256& hash = tx.GetHash(); + CAmount nTxFees = view.GetValueInExcess(tx); + mempool.ApplyDeltas(hash, dPriority, nTxFees); + + return CFeeRate(nTxFees, nTxSize); +} + CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) { // Create new block @@ -172,7 +180,6 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) continue; COrphan* porphan = NULL; - CAmount nTotalIn = 0; bool fMissingInputs = false; BOOST_FOREACH(const CTxIn& txin, tx.vin) { @@ -201,14 +208,10 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) } mapDependers[txin.prevout.hash].push_back(porphan); porphan->setDependsOn.insert(txin.prevout.hash); - nTotalIn += mempool.mapTx[txin.prevout.hash].GetTx().vout[txin.prevout.n].nValue; continue; } const CCoins* coins = view.AccessCoins(txin.prevout.hash); assert(coins); - - CAmount nValueIn = coins->vout[txin.prevout.n].nValue; - nTotalIn += nValueIn; } if (fMissingInputs) continue; @@ -216,18 +219,16 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); double dPriority = viewMemPool.GetPriority(tx, nHeight); - uint256 hash = tx.GetHash(); - mempool.ApplyDeltas(hash, dPriority, nTotalIn); - - CFeeRate feeRate(nTotalIn-tx.GetValueOut(), nTxSize); - if (porphan) { - porphan->dPriority = dPriority; - porphan->feeRate = feeRate; + porphan->dPriorityBeforeDelta = dPriority; + porphan->nTxSize = nTxSize; } else + { + const CFeeRate feeRate = CalculateSubjectiveFeeRateAndPriority(view, tx, nTxSize, dPriority); vecPriority.push_back(TxPriority(dPriority, feeRate, &mi->second.GetTx())); + } } // Collect transactions into block @@ -280,7 +281,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) if (!view.HaveInputs(tx)) continue; - CAmount nTxFees = view.GetValueIn(tx)-tx.GetValueOut(); + CAmount nTxFees = view.GetValueInExcess(tx); nTxSigOps += GetP2SHSigOpCount(tx, view); if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) @@ -321,7 +322,9 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) porphan->setDependsOn.erase(hash); if (porphan->setDependsOn.empty()) { - vecPriority.push_back(TxPriority(porphan->dPriority, porphan->feeRate, porphan->ptx)); + double dPriority = porphan->dPriorityBeforeDelta; + const CFeeRate feeRate = CalculateSubjectiveFeeRateAndPriority(view, *porphan->ptx, porphan->nTxSize, dPriority); + vecPriority.push_back(TxPriority(dPriority, feeRate, porphan->ptx)); std::push_heap(vecPriority.begin(), vecPriority.end(), comparer); } } @@ -392,7 +395,7 @@ CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey) bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) { LogPrintf("%s\n", pblock->ToString()); - LogPrintf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue)); + LogPrintf("generated\n"); // Found a solution { diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index 491f027aaf..94716036f2 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -9,6 +9,46 @@ #include "tinyformat.h" #include "utilstrencodings.h" +CTxOutValue::CTxOutValue() +: nAmount(-1) +{ +} + +CTxOutValue::CTxOutValue(CAmount nAmountIn) +: nAmount(nAmountIn) +{ +} + +bool CTxOutValue::IsValid() const +{ + return nAmount >= 0; +} + +bool CTxOutValue::IsNull() const +{ + return nAmount == -1; +} + +bool CTxOutValue::IsAmount() const +{ + return nAmount != -1; +} + +CAmount CTxOutValue::GetAmount() const +{ + assert(IsAmount()); + return nAmount; +} + +bool operator==(const CTxOutValue& a, const CTxOutValue& b) +{ + return a.nAmount == b.nAmount; +} + +bool operator!=(const CTxOutValue& a, const CTxOutValue& b) { + return !(a == b); +} + std::string COutPoint::ToString() const { return strprintf("COutPoint(%s, %u)", hash.ToString().substr(0,10), n); @@ -43,15 +83,15 @@ std::string CTxIn::ToString() const return str; } -CTxOut::CTxOut(const CAmount& nValueIn, CScript scriptPubKeyIn) +CTxOut::CTxOut(const CTxOutValue& valueIn, CScript scriptPubKeyIn) { - nValue = nValueIn; + nValue = valueIn; scriptPubKey = scriptPubKeyIn; } std::string CTxOut::ToString() const { - return strprintf("CTxOut(nValue=%d.%08d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,30)); + return strprintf("CTxOut(nValue=%s, scriptPubKey=%s)", (nValue.IsAmount() ? strprintf("%d.%08d", nValue.GetAmount() / COIN, nValue.GetAmount() % COIN) : std::string("UNKNOWN")), scriptPubKey.ToString().substr(0,30)); } CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nLockTime(0) {} @@ -87,8 +127,10 @@ CAmount CTransaction::GetValueOut() const CAmount nValueOut = 0; for (std::vector::const_iterator it(vout.begin()); it != vout.end(); ++it) { - nValueOut += it->nValue; - if (!MoneyRange(it->nValue) || !MoneyRange(nValueOut)) + assert(it->nValue.IsAmount()); + const CAmount nAmount = it->nValue.GetAmount(); + nValueOut += nAmount; + if (!MoneyRange(nAmount) || !MoneyRange(nValueOut)) throw std::runtime_error("CTransaction::GetValueOut() : value out of range"); } return nValueOut; diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 8e236d41f8..1f124d2694 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -11,6 +11,30 @@ #include "serialize.h" #include "uint256.h" +class CTxOutValue +{ + CAmount nAmount; +public: + CTxOutValue(); + CTxOutValue(CAmount); + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(nAmount); + } + + bool IsValid() const; + bool IsNull() const; + bool IsAmount() const; + + CAmount GetAmount() const; + + friend bool operator==(const CTxOutValue& a, const CTxOutValue& b); + friend bool operator!=(const CTxOutValue& a, const CTxOutValue& b); +}; + /** An outpoint - a combination of a transaction hash and an index n into its vout */ class COutPoint { @@ -98,7 +122,7 @@ public: class CTxOut { public: - CAmount nValue; + CTxOutValue nValue; CScript scriptPubKey; CTxOut() @@ -106,7 +130,7 @@ public: SetNull(); } - CTxOut(const CAmount& nValueIn, CScript scriptPubKeyIn); + CTxOut(const CTxOutValue& nValueIn, CScript scriptPubKeyIn); ADD_SERIALIZE_METHODS; @@ -129,6 +153,9 @@ public: bool IsDust(CFeeRate minRelayTxFee) const { + if (!nValue.IsAmount()) + return false; // FIXME + // "Dust" is defined in terms of CTransaction::minRelayTxFee, // which has units satoshis-per-kilobyte. // If you'd pay more than 1/3 in fees @@ -138,7 +165,7 @@ public: // so dust is a txout less than 546 satoshis // with default minRelayTxFee. size_t nSize = GetSerializeSize(SER_DISK,0)+148u; - return (nValue < 3*minRelayTxFee.GetFee(nSize)); + return (nValue.GetAmount() < 3*minRelayTxFee.GetFee(nSize)); } friend bool operator==(const CTxOut& a, const CTxOut& b) diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 147db97886..253c771ffd 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -321,7 +321,6 @@ Value gettxoutsetinfo(const Array& params, bool fHelp) ret.push_back(Pair("txouts", (int64_t)stats.nTransactionOutputs)); ret.push_back(Pair("bytes_serialized", (int64_t)stats.nSerializedSize)); ret.push_back(Pair("hash_serialized", stats.hashSerialized.GetHex())); - ret.push_back(Pair("total_amount", ValueFromAmount(stats.nTotalAmount))); } return ret; } @@ -394,7 +393,8 @@ Value gettxout(const Array& params, bool fHelp) ret.push_back(Pair("confirmations", 0)); else ret.push_back(Pair("confirmations", pindex->nHeight - coins.nHeight + 1)); - ret.push_back(Pair("value", ValueFromAmount(coins.vout[n].nValue))); + if (coins.vout[n].nValue.IsAmount()) + ret.push_back(Pair("value", ValueFromAmount(coins.vout[n].nValue.GetAmount()))); Object o; ScriptPubKeyToJSON(coins.vout[n].scriptPubKey, o, true); ret.push_back(Pair("scriptPubKey", o)); diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index e6ac4da6fb..3bad4d4890 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -661,7 +661,7 @@ Value getblocktemplate(const Array& params, bool fHelp) result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex())); result.push_back(Pair("transactions", transactions)); result.push_back(Pair("coinbaseaux", aux)); - result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue)); + result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue.GetAmount())); result.push_back(Pair("longpollid", chainActive.Tip()->GetBlockHash().GetHex() + i64tostr(nTransactionsUpdatedLast))); result.push_back(Pair("target", GetChallengeStrHex(*pblock))); result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1)); diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index 123b46f9a6..a4beebbf28 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -81,7 +81,8 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry) for (unsigned int i = 0; i < tx.vout.size(); i++) { const CTxOut& txout = tx.vout[i]; Object out; - out.push_back(Pair("value", ValueFromAmount(txout.nValue))); + if (txout.nValue.IsAmount()) + out.push_back(Pair("value", ValueFromAmount(txout.nValue.GetAmount()))); out.push_back(Pair("n", (int64_t)i)); Object o; ScriptPubKeyToJSON(txout.scriptPubKey, o, true); diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 5dbb8d3632..ae32a6a9c6 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -50,6 +50,7 @@ struct { // NOTE: These tests rely on CreateNewBlock doing its own self-validation! BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) { + CAmount nAmount; CScript scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG; CBlockTemplate *pblocktemplate; CMutableTransaction tx; @@ -104,10 +105,11 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vin[0].prevout.hash = txFirst[0]->GetHash(); tx.vin[0].prevout.n = 0; tx.vout.resize(1); - tx.vout[0].nValue = 5000000000LL; + nAmount = 5000000000LL; for (unsigned int i = 0; i < 1001; ++i) { - tx.vout[0].nValue -= 1000000; + nAmount -= 1000000; + tx.vout[0].nValue = nAmount; hash = tx.GetHash(); mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); tx.vin[0].prevout.hash = hash; @@ -124,10 +126,11 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vin[0].scriptSig << vchData << OP_DROP; tx.vin[0].scriptSig << OP_1; tx.vin[0].prevout.hash = txFirst[0]->GetHash(); - tx.vout[0].nValue = 5000000000LL; + nAmount = 5000000000LL; for (unsigned int i = 0; i < 128; ++i) { - tx.vout[0].nValue -= 10000000; + nAmount -= 10000000; + tx.vout[0].nValue = nAmount; hash = tx.GetHash(); mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); tx.vin[0].prevout.hash = hash; @@ -176,14 +179,16 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vin[0].prevout.hash = txFirst[0]->GetHash(); tx.vin[0].prevout.n = 0; tx.vin[0].scriptSig = CScript() << OP_1; - tx.vout[0].nValue = 4900000000LL; + nAmount = 4900000000LL; + tx.vout[0].nValue = nAmount; script = CScript() << OP_0; tx.vout[0].scriptPubKey = GetScriptForDestination(CScriptID(script)); hash = tx.GetHash(); mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); tx.vin[0].prevout.hash = hash; tx.vin[0].scriptSig = CScript() << (std::vector)script; - tx.vout[0].nValue -= 1000000; + nAmount -= 1000000; + tx.vout[0].nValue = nAmount; hash = tx.GetHash(); mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); diff --git a/src/txdb.cpp b/src/txdb.cpp index b47998b4bb..c12a156714 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -126,7 +126,6 @@ bool CCoinsViewDB::GetStats(CCoinsStats &stats) const { CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); stats.hashBlock = GetBestBlock(); ss << stats.hashBlock; - CAmount nTotalAmount = 0; while (pcursor->Valid()) { boost::this_thread::interruption_point(); try { @@ -152,7 +151,6 @@ bool CCoinsViewDB::GetStats(CCoinsStats &stats) const { stats.nTransactionOutputs++; ss << VARINT(i+1); ss << out; - nTotalAmount += out.nValue; } } stats.nSerializedSize += 32 + slValue.size(); @@ -165,7 +163,6 @@ bool CCoinsViewDB::GetStats(CCoinsStats &stats) const { } stats.nHeight = mapBlockIndex.find(GetBestBlock())->second->nHeight; stats.hashSerialized = ss.GetHash(); - stats.nTotalAmount = nTotalAmount; return true; } diff --git a/src/txmempool.cpp b/src/txmempool.cpp index db598a1dfa..51de5e3eb7 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -40,10 +40,15 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTxMemPoolEntry& other) double CTxMemPoolEntry::GetPriority(unsigned int currentHeight) const { +#if 0 // FIXME CAmount nValueIn = tx.GetValueOut()+nFee; double deltaPriority = ((double)(currentHeight-nHeight)*nValueIn)/nModSize; double dResult = dPriority + deltaPriority; return dResult; +#else + // I'm pretty sure this logic is broken anyway, so I'm not even going to try to fix it now + return dPriority; +#endif } /**