Skip to content

Commit b78d1cd

Browse files
committed
Merge pull request #3239 from gavinandresen/mempool_verbose
Add verbose flag to getrawmempool
2 parents e7e8a75 + 4d707d5 commit b78d1cd

16 files changed

+244
-139
lines changed

src/coins.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,3 +178,19 @@ bool CCoinsViewCache::HaveInputs(const CTransaction& tx)
178178
}
179179
return true;
180180
}
181+
182+
double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight)
183+
{
184+
if (tx.IsCoinBase())
185+
return 0.0;
186+
double dResult = 0.0;
187+
BOOST_FOREACH(const CTxIn& txin, tx.vin)
188+
{
189+
const CCoins &coins = GetCoins(txin.prevout.hash);
190+
if (!coins.IsAvailable(txin.prevout.n)) continue;
191+
if (coins.nHeight < nHeight) {
192+
dResult += coins.vout[txin.prevout.n].nValue * (nHeight-coins.nHeight);
193+
}
194+
}
195+
return tx.ComputePriority(dResult);
196+
}

src/coins.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,13 +340,15 @@ class CCoinsViewCache : public CCoinsViewBacked
340340
341341
@param[in] tx transaction for which we are checking input total
342342
@return Sum of value of all inputs (scriptSigs)
343-
@see CTransaction::FetchInputs
344343
*/
345344
int64_t GetValueIn(const CTransaction& tx);
346345

347346
// Check whether all prevouts of the transaction are present in the UTXO set represented by this view
348347
bool HaveInputs(const CTransaction& tx);
349348

349+
// Return priority of tx at height nHeight
350+
double GetPriority(const CTransaction &tx, int nHeight);
351+
350352
const CTxOut &GetOutputFor(const CTxIn& input);
351353

352354
private:

src/core.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,37 @@ bool CTransaction::IsNewerThan(const CTransaction& old) const
106106
return fNewer;
107107
}
108108

109+
int64_t CTransaction::GetValueOut() const
110+
{
111+
int64_t nValueOut = 0;
112+
BOOST_FOREACH(const CTxOut& txout, vout)
113+
{
114+
nValueOut += txout.nValue;
115+
if (!MoneyRange(txout.nValue) || !MoneyRange(nValueOut))
116+
throw std::runtime_error("CTransaction::GetValueOut() : value out of range");
117+
}
118+
return nValueOut;
119+
}
120+
121+
double CTransaction::ComputePriority(double dPriorityInputs, unsigned int nTxSize) const
122+
{
123+
// In order to avoid disincentivizing cleaning up the UTXO set we don't count
124+
// the constant overhead for each txin and up to 110 bytes of scriptSig (which
125+
// is enough to cover a compressed pubkey p2sh redemption) for priority.
126+
// Providing any more cleanup incentive than making additional inputs free would
127+
// risk encouraging people to create junk outputs to redeem later.
128+
if (nTxSize == 0)
129+
nTxSize = ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION);
130+
BOOST_FOREACH(const CTxIn& txin, vin)
131+
{
132+
unsigned int offset = 41U + std::min(110U, (unsigned int)txin.scriptSig.size());
133+
if (nTxSize > offset)
134+
nTxSize -= offset;
135+
}
136+
if (nTxSize == 0) return 0.0;
137+
return dPriorityInputs / nTxSize;
138+
}
139+
109140
std::string CTransaction::ToString() const
110141
{
111142
std::string str;

src/core.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414

1515
class CTransaction;
1616

17+
/** No amount larger than this (in satoshi) is valid */
18+
static const int64_t MAX_MONEY = 21000000 * COIN;
19+
inline bool MoneyRange(int64_t nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); }
20+
1721
/** An outpoint - a combination of a transaction hash and an index n into its vout */
1822
class COutPoint
1923
{
@@ -50,11 +54,11 @@ class COutPoint
5054
class CInPoint
5155
{
5256
public:
53-
CTransaction* ptx;
57+
const CTransaction* ptx;
5458
unsigned int n;
5559

5660
CInPoint() { SetNull(); }
57-
CInPoint(CTransaction* ptxIn, unsigned int nIn) { ptx = ptxIn; n = nIn; }
61+
CInPoint(const CTransaction* ptxIn, unsigned int nIn) { ptx = ptxIn; n = nIn; }
5862
void SetNull() { ptx = NULL; n = (unsigned int) -1; }
5963
bool IsNull() const { return (ptx == NULL && n == (unsigned int) -1); }
6064
};
@@ -217,6 +221,14 @@ class CTransaction
217221
uint256 GetHash() const;
218222
bool IsNewerThan(const CTransaction& old) const;
219223

224+
// Return sum of txouts.
225+
int64_t GetValueOut() const;
226+
// GetValueIn() is a method on CCoinsViewCache, because
227+
// inputs must be known to compute value in.
228+
229+
// Compute priority, given priority of inputs and (optionally) tx size
230+
double ComputePriority(double dPriorityInputs, unsigned int nTxSize=0) const;
231+
220232
bool IsCoinBase() const
221233
{
222234
return (vin.size() == 1 && vin[0].prevout.IsNull());

src/main.cpp

Lines changed: 14 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -379,21 +379,6 @@ bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime)
379379
return true;
380380
}
381381

382-
/** Amount of bitcoins spent by the transaction.
383-
@return sum of all outputs (note: does not include fees)
384-
*/
385-
int64_t GetValueOut(const CTransaction& tx)
386-
{
387-
int64_t nValueOut = 0;
388-
BOOST_FOREACH(const CTxOut& txout, tx.vout)
389-
{
390-
nValueOut += txout.nValue;
391-
if (!MoneyRange(txout.nValue) || !MoneyRange(nValueOut))
392-
throw std::runtime_error("GetValueOut() : value out of range");
393-
}
394-
return nValueOut;
395-
}
396-
397382
//
398383
// Check transaction inputs, and make sure any
399384
// pay-to-script-hash transactions are evaluating IsStandard scripts
@@ -660,7 +645,6 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
660645
return false;
661646

662647
// Check for conflicts with in-memory transactions
663-
CTransaction* ptxOld = NULL;
664648
{
665649
LOCK(pool.cs); // protect pool.mapNextTx
666650
for (unsigned int i = 0; i < tx.vin.size(); i++)
@@ -670,22 +654,6 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
670654
{
671655
// Disable replacement feature for now
672656
return false;
673-
674-
// Allow replacing with a newer version of the same transaction
675-
if (i != 0)
676-
return false;
677-
ptxOld = pool.mapNextTx[outpoint].ptx;
678-
if (IsFinalTx(*ptxOld))
679-
return false;
680-
if (!tx.IsNewerThan(*ptxOld))
681-
return false;
682-
for (unsigned int i = 0; i < tx.vin.size(); i++)
683-
{
684-
COutPoint outpoint = tx.vin[i].prevout;
685-
if (!pool.mapNextTx.count(outpoint) || pool.mapNextTx[outpoint].ptx != ptxOld)
686-
return false;
687-
}
688-
break;
689657
}
690658
}
691659
}
@@ -734,8 +702,13 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
734702
// you should add code here to check that the transaction does a
735703
// reasonable number of ECDSA signature verifications.
736704

737-
int64_t nFees = view.GetValueIn(tx)-GetValueOut(tx);
738-
unsigned int nSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
705+
int64_t nValueIn = view.GetValueIn(tx);
706+
int64_t nValueOut = tx.GetValueOut();
707+
int64_t nFees = nValueIn-nValueOut;
708+
double dPriority = view.GetPriority(tx, chainActive.Height());
709+
710+
CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height());
711+
unsigned int nSize = entry.GetTxSize();
739712

740713
// Don't accept it if it can't get into a block
741714
int64_t txMinFee = GetMinFee(tx, nSize, true, GMF_RELAY);
@@ -779,22 +752,10 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
779752
{
780753
return error("AcceptToMemoryPool: : ConnectInputs failed %s", hash.ToString().c_str());
781754
}
755+
// Store transaction in memory
756+
pool.addUnchecked(hash, entry);
782757
}
783758

784-
// Store transaction in memory
785-
{
786-
if (ptxOld)
787-
{
788-
LogPrint("mempool", "AcceptToMemoryPool: : replacing tx %s with new version\n", ptxOld->GetHash().ToString().c_str());
789-
pool.remove(*ptxOld);
790-
}
791-
pool.addUnchecked(hash, tx);
792-
}
793-
794-
///// are we sure this is ok when loading transactions or restoring block txes
795-
// If updated, erase old tx from wallet
796-
if (ptxOld)
797-
g_signals.EraseTransaction(ptxOld->GetHash());
798759
g_signals.SyncTransaction(hash, tx, NULL);
799760

800761
return true;
@@ -1370,12 +1331,12 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, CCoinsViewCach
13701331

13711332
}
13721333

1373-
if (nValueIn < GetValueOut(tx))
1334+
if (nValueIn < tx.GetValueOut())
13741335
return state.DoS(100, error("CheckInputs() : %s value in < value out", tx.GetHash().ToString().c_str()),
13751336
REJECT_INVALID, "in < out");
13761337

13771338
// Tally transaction fees
1378-
int64_t nTxFee = nValueIn - GetValueOut(tx);
1339+
int64_t nTxFee = nValueIn - tx.GetValueOut();
13791340
if (nTxFee < 0)
13801341
return state.DoS(100, error("CheckInputs() : %s nTxFee < 0", tx.GetHash().ToString().c_str()),
13811342
REJECT_INVALID, "fee < 0");
@@ -1628,7 +1589,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
16281589
REJECT_INVALID, "too many sigops");
16291590
}
16301591

1631-
nFees += view.GetValueIn(tx)-GetValueOut(tx);
1592+
nFees += view.GetValueIn(tx)-tx.GetValueOut();
16321593

16331594
std::vector<CScriptCheck> vChecks;
16341595
if (!CheckInputs(tx, state, view, fScriptChecks, flags, nScriptCheckThreads ? &vChecks : NULL))
@@ -1648,10 +1609,10 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
16481609
if (fBenchmark)
16491610
LogPrintf("- Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin)\n", (unsigned)block.vtx.size(), 0.001 * nTime, 0.001 * nTime / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * nTime / (nInputs-1));
16501611

1651-
if (GetValueOut(block.vtx[0]) > GetBlockValue(pindex->nHeight, nFees))
1612+
if (block.vtx[0].GetValueOut() > GetBlockValue(pindex->nHeight, nFees))
16521613
return state.DoS(100,
16531614
error("ConnectBlock() : coinbase pays too much (actual=%"PRId64" vs limit=%"PRId64")",
1654-
GetValueOut(block.vtx[0]), GetBlockValue(pindex->nHeight, nFees)),
1615+
block.vtx[0].GetValueOut(), GetBlockValue(pindex->nHeight, nFees)),
16551616
REJECT_INVALID, "coinbase too large");
16561617

16571618
if (!control.Wait())

src/main.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,6 @@ static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB
4949
static const unsigned int BLOCKFILE_CHUNK_SIZE = 0x1000000; // 16 MiB
5050
/** The pre-allocation chunk size for rev?????.dat files (since 0.8) */
5151
static const unsigned int UNDOFILE_CHUNK_SIZE = 0x100000; // 1 MiB
52-
/** No amount larger than this (in satoshi) is valid */
53-
static const int64_t MAX_MONEY = 21000000 * COIN;
54-
inline bool MoneyRange(int64_t nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); }
5552
/** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */
5653
static const int COINBASE_MATURITY = 100;
5754
/** Threshold for nLockTime: below this value it is interpreted as block number, otherwise as UNIX timestamp. */
@@ -320,11 +317,6 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason);
320317

321318
bool IsFinalTx(const CTransaction &tx, int nBlockHeight = 0, int64_t nBlockTime = 0);
322319

323-
/** Amount of bitcoins spent by the transaction.
324-
@return sum of all outputs (note: does not include fees)
325-
*/
326-
int64_t GetValueOut(const CTransaction& tx);
327-
328320
/** Undo information for a CBlock */
329321
class CBlockUndo
330322
{

src/miner.cpp

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -93,12 +93,12 @@ unsigned int static ScanHash_CryptoPP(char* pmidstate, char* pdata, char* phash1
9393
class COrphan
9494
{
9595
public:
96-
CTransaction* ptx;
96+
const CTransaction* ptx;
9797
set<uint256> setDependsOn;
9898
double dPriority;
9999
double dFeePerKb;
100100

101-
COrphan(CTransaction* ptxIn)
101+
COrphan(const CTransaction* ptxIn)
102102
{
103103
ptx = ptxIn;
104104
dPriority = dFeePerKb = 0;
@@ -118,7 +118,7 @@ uint64_t nLastBlockTx = 0;
118118
uint64_t nLastBlockSize = 0;
119119

120120
// We want to sort transactions by priority and fee, so:
121-
typedef boost::tuple<double, double, CTransaction*> TxPriority;
121+
typedef boost::tuple<double, double, const CTransaction*> TxPriority;
122122
class TxPriorityCompare
123123
{
124124
bool byFee;
@@ -191,9 +191,10 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
191191
// This vector will be sorted into a priority queue:
192192
vector<TxPriority> vecPriority;
193193
vecPriority.reserve(mempool.mapTx.size());
194-
for (map<uint256, CTransaction>::iterator mi = mempool.mapTx.begin(); mi != mempool.mapTx.end(); ++mi)
194+
for (map<uint256, CTxMemPoolEntry>::iterator mi = mempool.mapTx.begin();
195+
mi != mempool.mapTx.end(); ++mi)
195196
{
196-
CTransaction& tx = (*mi).second;
197+
const CTransaction& tx = mi->second.GetTx();
197198
if (tx.IsCoinBase() || !IsFinalTx(tx))
198199
continue;
199200

@@ -228,7 +229,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
228229
}
229230
mapDependers[txin.prevout.hash].push_back(porphan);
230231
porphan->setDependsOn.insert(txin.prevout.hash);
231-
nTotalIn += mempool.mapTx[txin.prevout.hash].vout[txin.prevout.n].nValue;
232+
nTotalIn += mempool.mapTx[txin.prevout.hash].GetTx().vout[txin.prevout.n].nValue;
232233
continue;
233234
}
234235
const CCoins &coins = view.GetCoins(txin.prevout.hash);
@@ -244,32 +245,20 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
244245

245246
// Priority is sum(valuein * age) / modified_txsize
246247
unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
247-
unsigned int nTxSizeMod = nTxSize;
248-
// In order to avoid disincentivizing cleaning up the UTXO set we don't count
249-
// the constant overhead for each txin and up to 110 bytes of scriptSig (which
250-
// is enough to cover a compressed pubkey p2sh redemption) for priority.
251-
// Providing any more cleanup incentive than making additional inputs free would
252-
// risk encouraging people to create junk outputs to redeem later.
253-
BOOST_FOREACH(const CTxIn& txin, tx.vin)
254-
{
255-
unsigned int offset = 41U + min(110U, (unsigned int)txin.scriptSig.size());
256-
if (nTxSizeMod > offset)
257-
nTxSizeMod -= offset;
258-
}
259-
dPriority /= nTxSizeMod;
248+
dPriority = tx.ComputePriority(dPriority, nTxSize);
260249

261250
// This is a more accurate fee-per-kilobyte than is used by the client code, because the
262251
// client code rounds up the size to the nearest 1K. That's good, because it gives an
263252
// incentive to create smaller transactions.
264-
double dFeePerKb = double(nTotalIn-GetValueOut(tx)) / (double(nTxSize)/1000.0);
253+
double dFeePerKb = double(nTotalIn-tx.GetValueOut()) / (double(nTxSize)/1000.0);
265254

266255
if (porphan)
267256
{
268257
porphan->dPriority = dPriority;
269258
porphan->dFeePerKb = dFeePerKb;
270259
}
271260
else
272-
vecPriority.push_back(TxPriority(dPriority, dFeePerKb, &(*mi).second));
261+
vecPriority.push_back(TxPriority(dPriority, dFeePerKb, &mi->second.GetTx()));
273262
}
274263

275264
// Collect transactions into block
@@ -286,7 +275,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
286275
// Take highest priority transaction off the priority queue:
287276
double dPriority = vecPriority.front().get<0>();
288277
double dFeePerKb = vecPriority.front().get<1>();
289-
CTransaction& tx = *(vecPriority.front().get<2>());
278+
const CTransaction& tx = *(vecPriority.front().get<2>());
290279

291280
std::pop_heap(vecPriority.begin(), vecPriority.end(), comparer);
292281
vecPriority.pop_back();
@@ -318,7 +307,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
318307
if (!view.HaveInputs(tx))
319308
continue;
320309

321-
int64_t nTxFees = view.GetValueIn(tx)-GetValueOut(tx);
310+
int64_t nTxFees = view.GetValueIn(tx)-tx.GetValueOut();
322311

323312
nTxSigOps += GetP2SHSigOpCount(tx, view);
324313
if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)

src/qt/transactiondesc.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, int vout, int u
194194
strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(unit, nValue) + "<br>";
195195
}
196196

197-
int64_t nTxFee = nDebit - GetValueOut(wtx);
197+
int64_t nTxFee = nDebit - wtx.GetValueOut();
198198
if (nTxFee > 0)
199199
strHTML += "<b>" + tr("Transaction fee") + ":</b> " + BitcoinUnits::formatWithUnit(unit, -nTxFee) + "<br>";
200200
}

src/qt/transactionrecord.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
9595
//
9696
// Debit
9797
//
98-
int64_t nTxFee = nDebit - GetValueOut(wtx);
98+
int64_t nTxFee = nDebit - wtx.GetValueOut();
9999

100100
for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++)
101101
{

0 commit comments

Comments
 (0)