Skip to content

Commit 4d707d5

Browse files
committed
Add verbose boolean to getrawmempool
Also changes mempool to store CTxMemPoolEntries to keep track of when they enter/exit the pool.
1 parent 0733c1b commit 4d707d5

File tree

12 files changed

+212
-76
lines changed

12 files changed

+212
-76
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 & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,9 @@ class CCoinsViewCache : public CCoinsViewBacked
346346
// Check whether all prevouts of the transaction are present in the UTXO set represented by this view
347347
bool HaveInputs(const CTransaction& tx);
348348

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

351354
private:

src/core.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,25 @@ int64_t CTransaction::GetValueOut() const
118118
return nValueOut;
119119
}
120120

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+
121140
std::string CTransaction::ToString() const
122141
{
123142
std::string str;

src/core.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,11 @@ class COutPoint
5454
class CInPoint
5555
{
5656
public:
57-
CTransaction* ptx;
57+
const CTransaction* ptx;
5858
unsigned int n;
5959

6060
CInPoint() { SetNull(); }
61-
CInPoint(CTransaction* ptxIn, unsigned int nIn) { ptx = ptxIn; n = nIn; }
61+
CInPoint(const CTransaction* ptxIn, unsigned int nIn) { ptx = ptxIn; n = nIn; }
6262
void SetNull() { ptx = NULL; n = (unsigned int) -1; }
6363
bool IsNull() const { return (ptx == NULL && n == (unsigned int) -1); }
6464
};
@@ -226,6 +226,9 @@ class CTransaction
226226
// GetValueIn() is a method on CCoinsViewCache, because
227227
// inputs must be known to compute value in.
228228

229+
// Compute priority, given priority of inputs and (optionally) tx size
230+
double ComputePriority(double dPriorityInputs, unsigned int nTxSize=0) const;
231+
229232
bool IsCoinBase() const
230233
{
231234
return (vin.size() == 1 && vin[0].prevout.IsNull());

src/main.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -702,8 +702,13 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
702702
// you should add code here to check that the transaction does a
703703
// reasonable number of ECDSA signature verifications.
704704

705-
int64_t nFees = view.GetValueIn(tx)-tx.GetValueOut();
706-
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();
707712

708713
// Don't accept it if it can't get into a block
709714
int64_t txMinFee = GetMinFee(tx, nSize, true, GMF_RELAY);
@@ -747,11 +752,10 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
747752
{
748753
return error("AcceptToMemoryPool: : ConnectInputs failed %s", hash.ToString().c_str());
749754
}
755+
// Store transaction in memory
756+
pool.addUnchecked(hash, entry);
750757
}
751758

752-
// Store transaction in memory
753-
pool.addUnchecked(hash, tx);
754-
755759
g_signals.SyncTransaction(hash, tx, NULL);
756760

757761
return true;

src/miner.cpp

Lines changed: 10 additions & 21 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,19 +245,7 @@ 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
@@ -269,7 +258,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
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();

src/rpcblockchain.cpp

Lines changed: 63 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -153,28 +153,79 @@ Value settxfee(const Array& params, bool fHelp)
153153

154154
Value getrawmempool(const Array& params, bool fHelp)
155155
{
156-
if (fHelp || params.size() != 0)
156+
if (fHelp || params.size() > 1)
157157
throw runtime_error(
158-
"getrawmempool\n"
158+
"getrawmempool ( verbose )\n"
159159
"\nReturns all transaction ids in memory pool as a json array of string transaction ids.\n"
160-
"\nResult:\n"
161-
"[ (json array of string)\n"
160+
"\nArguments:\n"
161+
"1. verbose (boolean, optional, default=false) true for a json object, false for array of transaction ids\n"
162+
"\nResult: (for verbose = false):\n"
163+
"[ (json array of string)\n"
162164
" \"transactionid\" (string) The transaction id\n"
163165
" ,...\n"
164166
"]\n"
167+
"\nResult: (for verbose = true):\n"
168+
"{ (json object)\n"
169+
" \"transactionid\" : { (json object)\n"
170+
" \"size\" : n, (numeric) transaction size in bytes\n"
171+
" \"fee\" : n, (numeric) transaction fee in bitcoins\n"
172+
" \"time\" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT\n"
173+
" \"height\" : n, (numeric) block height when transaction entered pool\n"
174+
" \"startingpriority\" : n, (numeric) priority when transaction entered pool\n"
175+
" \"currentpriority\" : n, (numeric) transaction priority now\n"
176+
" \"depends\" : [ (array) unconfirmed transactions used as inputs for this transaction\n"
177+
" \"transactionid\", (string) parent transaction id\n"
178+
" ... ]\n"
179+
" }, ...\n"
180+
"]\n"
165181
"\nExamples\n"
166-
+ HelpExampleCli("getrawmempool", "")
167-
+ HelpExampleRpc("getrawmempool", "")
182+
+ HelpExampleCli("getrawmempool", "true")
183+
+ HelpExampleRpc("getrawmempool", "true")
168184
);
169185

170-
vector<uint256> vtxid;
171-
mempool.queryHashes(vtxid);
186+
bool fVerbose = false;
187+
if (params.size() > 0)
188+
fVerbose = params[0].get_bool();
189+
190+
if (fVerbose)
191+
{
192+
LOCK(mempool.cs);
193+
Object o;
194+
BOOST_FOREACH(const PAIRTYPE(uint256, CTxMemPoolEntry)& entry, mempool.mapTx)
195+
{
196+
const uint256& hash = entry.first;
197+
const CTxMemPoolEntry& e = entry.second;
198+
Object info;
199+
info.push_back(Pair("size", (int)e.GetTxSize()));
200+
info.push_back(Pair("fee", ValueFromAmount(e.GetFee())));
201+
info.push_back(Pair("time", (boost::int64_t)e.GetTime()));
202+
info.push_back(Pair("height", (int)e.GetHeight()));
203+
info.push_back(Pair("startingpriority", e.GetPriority(e.GetHeight())));
204+
info.push_back(Pair("currentpriority", e.GetPriority(chainActive.Height())));
205+
const CTransaction& tx = e.GetTx();
206+
set<string> setDepends;
207+
BOOST_FOREACH(const CTxIn& txin, tx.vin)
208+
{
209+
if (mempool.exists(txin.prevout.hash))
210+
setDepends.insert(txin.prevout.hash.ToString());
211+
}
212+
Array depends(setDepends.begin(), setDepends.end());
213+
info.push_back(Pair("depends", depends));
214+
o.push_back(Pair(hash.ToString(), info));
215+
}
216+
return o;
217+
}
218+
else
219+
{
220+
vector<uint256> vtxid;
221+
mempool.queryHashes(vtxid);
172222

173-
Array a;
174-
BOOST_FOREACH(const uint256& hash, vtxid)
175-
a.push_back(hash.ToString());
223+
Array a;
224+
BOOST_FOREACH(const uint256& hash, vtxid)
225+
a.push_back(hash.ToString());
176226

177-
return a;
227+
return a;
228+
}
178229
}
179230

180231
Value getblockhash(const Array& params, bool fHelp)

src/rpcclient.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector<std::stri
176176
if (strMethod == "verifychain" && n > 0) ConvertTo<boost::int64_t>(params[0]);
177177
if (strMethod == "verifychain" && n > 1) ConvertTo<boost::int64_t>(params[1]);
178178
if (strMethod == "keypoolrefill" && n > 0) ConvertTo<boost::int64_t>(params[0]);
179+
if (strMethod == "getrawmempool" && n > 0) ConvertTo<bool>(params[0]);
179180

180181
return params;
181182
}

src/test/miner_tests.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
9999
{
100100
tx.vout[0].nValue -= 1000000;
101101
hash = tx.GetHash();
102-
mempool.addUnchecked(hash, tx);
102+
mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
103103
tx.vin[0].prevout.hash = hash;
104104
}
105105
BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey));
@@ -119,7 +119,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
119119
{
120120
tx.vout[0].nValue -= 10000000;
121121
hash = tx.GetHash();
122-
mempool.addUnchecked(hash, tx);
122+
mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
123123
tx.vin[0].prevout.hash = hash;
124124
}
125125
BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey));
@@ -128,7 +128,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
128128

129129
// orphan in mempool
130130
hash = tx.GetHash();
131-
mempool.addUnchecked(hash, tx);
131+
mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
132132
BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey));
133133
delete pblocktemplate;
134134
mempool.clear();
@@ -138,15 +138,15 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
138138
tx.vin[0].prevout.hash = txFirst[1]->GetHash();
139139
tx.vout[0].nValue = 4900000000LL;
140140
hash = tx.GetHash();
141-
mempool.addUnchecked(hash, tx);
141+
mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
142142
tx.vin[0].prevout.hash = hash;
143143
tx.vin.resize(2);
144144
tx.vin[1].scriptSig = CScript() << OP_1;
145145
tx.vin[1].prevout.hash = txFirst[0]->GetHash();
146146
tx.vin[1].prevout.n = 0;
147147
tx.vout[0].nValue = 5900000000LL;
148148
hash = tx.GetHash();
149-
mempool.addUnchecked(hash, tx);
149+
mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
150150
BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey));
151151
delete pblocktemplate;
152152
mempool.clear();
@@ -157,7 +157,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
157157
tx.vin[0].scriptSig = CScript() << OP_0 << OP_1;
158158
tx.vout[0].nValue = 0;
159159
hash = tx.GetHash();
160-
mempool.addUnchecked(hash, tx);
160+
mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
161161
BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey));
162162
delete pblocktemplate;
163163
mempool.clear();
@@ -170,12 +170,12 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
170170
script = CScript() << OP_0;
171171
tx.vout[0].scriptPubKey.SetDestination(script.GetID());
172172
hash = tx.GetHash();
173-
mempool.addUnchecked(hash, tx);
173+
mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
174174
tx.vin[0].prevout.hash = hash;
175175
tx.vin[0].scriptSig = CScript() << (std::vector<unsigned char>)script;
176176
tx.vout[0].nValue -= 1000000;
177177
hash = tx.GetHash();
178-
mempool.addUnchecked(hash,tx);
178+
mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
179179
BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey));
180180
delete pblocktemplate;
181181
mempool.clear();
@@ -186,10 +186,10 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
186186
tx.vout[0].nValue = 4900000000LL;
187187
tx.vout[0].scriptPubKey = CScript() << OP_1;
188188
hash = tx.GetHash();
189-
mempool.addUnchecked(hash, tx);
189+
mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
190190
tx.vout[0].scriptPubKey = CScript() << OP_2;
191191
hash = tx.GetHash();
192-
mempool.addUnchecked(hash, tx);
192+
mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
193193
BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey));
194194
delete pblocktemplate;
195195
mempool.clear();

0 commit comments

Comments
 (0)