Skip to content

Commit 4077ad2

Browse files
committed
Merge pull request #6898
553cad9 Rewrite CreateNewBlock (Alex Morcos) 5f12263 Expose FormatStateMessage (Alex Morcos) 1f09287 Make accessing mempool parents and children public (Alex Morcos) 7230187 Add TxPriority class and comparator (Alex Morcos) f3fe836 Add a score index to the mempool. (Alex Morcos) c49d5bc Store the total sig op count of a tx. (Alex Morcos)
2 parents 16f4a6e + 553cad9 commit 4077ad2

File tree

10 files changed

+293
-228
lines changed

10 files changed

+293
-228
lines changed

src/main.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -816,7 +816,7 @@ CAmount GetMinRelayFee(const CTransaction& tx, const CTxMemPool& pool, unsigned
816816
}
817817

818818
/** Convert CValidationState to a human-readable message for logging */
819-
static std::string FormatStateMessage(const CValidationState &state)
819+
std::string FormatStateMessage(const CValidationState &state)
820820
{
821821
return strprintf("%s%s (code %i)",
822822
state.GetRejectReason(),
@@ -964,7 +964,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
964964
}
965965
}
966966

967-
CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), pool.HasNoInputsOf(tx), inChainInputValue, fSpendsCoinbase);
967+
CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), pool.HasNoInputsOf(tx), inChainInputValue, fSpendsCoinbase, nSigOps);
968968
unsigned int nSize = entry.GetTxSize();
969969

970970
// Don't accept it if it can't get into a block

src/main.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,8 @@ void PruneAndFlush();
257257
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
258258
bool* pfMissingInputs, bool fOverrideMempoolLimit=false, bool fRejectAbsurdFee=false);
259259

260+
/** Convert CValidationState to a human-readable message for logging */
261+
std::string FormatStateMessage(const CValidationState &state);
260262

261263
struct CNodeStateStats {
262264
int nMisbehavior;

src/miner.cpp

Lines changed: 120 additions & 181 deletions
Large diffs are not rendered by default.

src/rpcblockchain.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ UniValue mempoolToJSON(bool fVerbose = false)
190190
UniValue info(UniValue::VOBJ);
191191
info.push_back(Pair("size", (int)e.GetTxSize()));
192192
info.push_back(Pair("fee", ValueFromAmount(e.GetFee())));
193+
info.push_back(Pair("modifiedfee", ValueFromAmount(e.GetModifiedFee())));
193194
info.push_back(Pair("time", e.GetTime()));
194195
info.push_back(Pair("height", (int)e.GetHeight()));
195196
info.push_back(Pair("startingpriority", e.GetPriority(e.GetHeight())));
@@ -247,6 +248,7 @@ UniValue getrawmempool(const UniValue& params, bool fHelp)
247248
" \"transactionid\" : { (json object)\n"
248249
" \"size\" : n, (numeric) transaction size in bytes\n"
249250
" \"fee\" : n, (numeric) transaction fee in " + CURRENCY_UNIT + "\n"
251+
" \"modifiedfee\" : n, (numeric) transaction fee with fee deltas used for mining priority\n"
250252
" \"time\" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT\n"
251253
" \"height\" : n, (numeric) block height when transaction entered pool\n"
252254
" \"startingpriority\" : n, (numeric) priority when transaction entered pool\n"

src/test/mempool_tests.cpp

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,13 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest)
102102
removed.clear();
103103
}
104104

105+
template<int index>
105106
void CheckSort(CTxMemPool &pool, std::vector<std::string> &sortedOrder)
106107
{
107108
BOOST_CHECK_EQUAL(pool.size(), sortedOrder.size());
108-
CTxMemPool::indexed_transaction_set::nth_index<1>::type::iterator it = pool.mapTx.get<1>().begin();
109+
typename CTxMemPool::indexed_transaction_set::nth_index<index>::type::iterator it = pool.mapTx.get<index>().begin();
109110
int count=0;
110-
for (; it != pool.mapTx.get<1>().end(); ++it, ++count) {
111+
for (; it != pool.mapTx.get<index>().end(); ++it, ++count) {
111112
BOOST_CHECK_EQUAL(it->GetTx().GetHash().ToString(), sortedOrder[count]);
112113
}
113114
}
@@ -163,7 +164,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
163164
sortedOrder[2] = tx1.GetHash().ToString(); // 10000
164165
sortedOrder[3] = tx4.GetHash().ToString(); // 15000
165166
sortedOrder[4] = tx2.GetHash().ToString(); // 20000
166-
CheckSort(pool, sortedOrder);
167+
CheckSort<1>(pool, sortedOrder);
167168

168169
/* low fee but with high fee child */
169170
/* tx6 -> tx7 -> tx8, tx9 -> tx10 */
@@ -175,7 +176,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
175176
BOOST_CHECK_EQUAL(pool.size(), 6);
176177
// Check that at this point, tx6 is sorted low
177178
sortedOrder.insert(sortedOrder.begin(), tx6.GetHash().ToString());
178-
CheckSort(pool, sortedOrder);
179+
CheckSort<1>(pool, sortedOrder);
179180

180181
CTxMemPool::setEntries setAncestors;
181182
setAncestors.insert(pool.mapTx.find(tx6.GetHash()));
@@ -201,7 +202,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
201202
sortedOrder.erase(sortedOrder.begin());
202203
sortedOrder.push_back(tx6.GetHash().ToString());
203204
sortedOrder.push_back(tx7.GetHash().ToString());
204-
CheckSort(pool, sortedOrder);
205+
CheckSort<1>(pool, sortedOrder);
205206

206207
/* low fee child of tx7 */
207208
CMutableTransaction tx8 = CMutableTransaction();
@@ -216,7 +217,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
216217

217218
// Now tx8 should be sorted low, but tx6/tx both high
218219
sortedOrder.insert(sortedOrder.begin(), tx8.GetHash().ToString());
219-
CheckSort(pool, sortedOrder);
220+
CheckSort<1>(pool, sortedOrder);
220221

221222
/* low fee child of tx7 */
222223
CMutableTransaction tx9 = CMutableTransaction();
@@ -231,7 +232,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
231232
// tx9 should be sorted low
232233
BOOST_CHECK_EQUAL(pool.size(), 9);
233234
sortedOrder.insert(sortedOrder.begin(), tx9.GetHash().ToString());
234-
CheckSort(pool, sortedOrder);
235+
CheckSort<1>(pool, sortedOrder);
235236

236237
std::vector<std::string> snapshotOrder = sortedOrder;
237238

@@ -273,17 +274,50 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
273274
sortedOrder.insert(sortedOrder.begin()+5, tx9.GetHash().ToString());
274275
sortedOrder.insert(sortedOrder.begin()+6, tx8.GetHash().ToString());
275276
sortedOrder.insert(sortedOrder.begin()+7, tx10.GetHash().ToString()); // tx10 is just before tx6
276-
CheckSort(pool, sortedOrder);
277+
CheckSort<1>(pool, sortedOrder);
277278

278279
// there should be 10 transactions in the mempool
279280
BOOST_CHECK_EQUAL(pool.size(), 10);
280281

281282
// Now try removing tx10 and verify the sort order returns to normal
282283
std::list<CTransaction> removed;
283284
pool.remove(pool.mapTx.find(tx10.GetHash())->GetTx(), removed, true);
284-
CheckSort(pool, snapshotOrder);
285+
CheckSort<1>(pool, snapshotOrder);
286+
287+
pool.remove(pool.mapTx.find(tx9.GetHash())->GetTx(), removed, true);
288+
pool.remove(pool.mapTx.find(tx8.GetHash())->GetTx(), removed, true);
289+
/* Now check the sort on the mining score index.
290+
* Final order should be:
291+
*
292+
* tx7 (2M)
293+
* tx2 (20k)
294+
* tx4 (15000)
295+
* tx1/tx5 (10000)
296+
* tx3/6 (0)
297+
* (Ties resolved by hash)
298+
*/
299+
sortedOrder.clear();
300+
sortedOrder.push_back(tx7.GetHash().ToString());
301+
sortedOrder.push_back(tx2.GetHash().ToString());
302+
sortedOrder.push_back(tx4.GetHash().ToString());
303+
if (tx1.GetHash() < tx5.GetHash()) {
304+
sortedOrder.push_back(tx5.GetHash().ToString());
305+
sortedOrder.push_back(tx1.GetHash().ToString());
306+
} else {
307+
sortedOrder.push_back(tx1.GetHash().ToString());
308+
sortedOrder.push_back(tx5.GetHash().ToString());
309+
}
310+
if (tx3.GetHash() < tx6.GetHash()) {
311+
sortedOrder.push_back(tx6.GetHash().ToString());
312+
sortedOrder.push_back(tx3.GetHash().ToString());
313+
} else {
314+
sortedOrder.push_back(tx3.GetHash().ToString());
315+
sortedOrder.push_back(tx6.GetHash().ToString());
316+
}
317+
CheckSort<3>(pool, sortedOrder);
285318
}
286319

320+
287321
BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
288322
{
289323
CTxMemPool pool(CFeeRate(1000));

src/test/miner_tests.cpp

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,22 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
120120
tx.vout[0].nValue -= 1000000;
121121
hash = tx.GetHash();
122122
bool spendsCoinbase = (i == 0) ? true : false; // only first tx spends coinbase
123-
mempool.addUnchecked(hash, entry.Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx));
123+
// If we don't set the # of sig ops in the CTxMemPoolEntry, template creation fails
124+
mempool.addUnchecked(hash, entry.Fee(1000000).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx));
125+
tx.vin[0].prevout.hash = hash;
126+
}
127+
BOOST_CHECK_THROW(CreateNewBlock(chainparams, scriptPubKey), std::runtime_error);
128+
mempool.clear();
129+
130+
tx.vin[0].prevout.hash = txFirst[0]->GetHash();
131+
tx.vout[0].nValue = 5000000000LL;
132+
for (unsigned int i = 0; i < 1001; ++i)
133+
{
134+
tx.vout[0].nValue -= 1000000;
135+
hash = tx.GetHash();
136+
bool spendsCoinbase = (i == 0) ? true : false; // only first tx spends coinbase
137+
// If we do set the # of sig ops in the CTxMemPoolEntry, template creation passes
138+
mempool.addUnchecked(hash, entry.Fee(1000000).Time(GetTime()).SpendsCoinbase(spendsCoinbase).SigOps(20).FromTx(tx));
124139
tx.vin[0].prevout.hash = hash;
125140
}
126141
BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey));
@@ -141,79 +156,76 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
141156
tx.vout[0].nValue -= 10000000;
142157
hash = tx.GetHash();
143158
bool spendsCoinbase = (i == 0) ? true : false; // only first tx spends coinbase
144-
mempool.addUnchecked(hash, entry.Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx));
159+
mempool.addUnchecked(hash, entry.Fee(1000000).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx));
145160
tx.vin[0].prevout.hash = hash;
146161
}
147162
BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey));
148163
delete pblocktemplate;
149164
mempool.clear();
150165

151-
// orphan in mempool
166+
// orphan in mempool, template creation fails
152167
hash = tx.GetHash();
153-
mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx));
154-
BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey));
155-
delete pblocktemplate;
168+
mempool.addUnchecked(hash, entry.Fee(1000000).Time(GetTime()).FromTx(tx));
169+
BOOST_CHECK_THROW(CreateNewBlock(chainparams, scriptPubKey), std::runtime_error);
156170
mempool.clear();
157171

158172
// child with higher priority than parent
159173
tx.vin[0].scriptSig = CScript() << OP_1;
160174
tx.vin[0].prevout.hash = txFirst[1]->GetHash();
161175
tx.vout[0].nValue = 4900000000LL;
162176
hash = tx.GetHash();
163-
mempool.addUnchecked(hash, entry.Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
177+
mempool.addUnchecked(hash, entry.Fee(100000000LL).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
164178
tx.vin[0].prevout.hash = hash;
165179
tx.vin.resize(2);
166180
tx.vin[1].scriptSig = CScript() << OP_1;
167181
tx.vin[1].prevout.hash = txFirst[0]->GetHash();
168182
tx.vin[1].prevout.n = 0;
169183
tx.vout[0].nValue = 5900000000LL;
170184
hash = tx.GetHash();
171-
mempool.addUnchecked(hash, entry.Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
185+
mempool.addUnchecked(hash, entry.Fee(400000000LL).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
172186
BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey));
173187
delete pblocktemplate;
174188
mempool.clear();
175189

176-
// coinbase in mempool
190+
// coinbase in mempool, template creation fails
177191
tx.vin.resize(1);
178192
tx.vin[0].prevout.SetNull();
179193
tx.vin[0].scriptSig = CScript() << OP_0 << OP_1;
180194
tx.vout[0].nValue = 0;
181195
hash = tx.GetHash();
182-
mempool.addUnchecked(hash, entry.Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
183-
BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey));
184-
delete pblocktemplate;
196+
// give it a fee so it'll get mined
197+
mempool.addUnchecked(hash, entry.Fee(100000).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
198+
BOOST_CHECK_THROW(CreateNewBlock(chainparams, scriptPubKey), std::runtime_error);
185199
mempool.clear();
186200

187-
// invalid (pre-p2sh) txn in mempool
201+
// invalid (pre-p2sh) txn in mempool, template creation fails
188202
tx.vin[0].prevout.hash = txFirst[0]->GetHash();
189203
tx.vin[0].prevout.n = 0;
190204
tx.vin[0].scriptSig = CScript() << OP_1;
191205
tx.vout[0].nValue = 4900000000LL;
192206
script = CScript() << OP_0;
193207
tx.vout[0].scriptPubKey = GetScriptForDestination(CScriptID(script));
194208
hash = tx.GetHash();
195-
mempool.addUnchecked(hash, entry.Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
209+
mempool.addUnchecked(hash, entry.Fee(10000000L).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
196210
tx.vin[0].prevout.hash = hash;
197211
tx.vin[0].scriptSig = CScript() << std::vector<unsigned char>(script.begin(), script.end());
198212
tx.vout[0].nValue -= 1000000;
199213
hash = tx.GetHash();
200-
mempool.addUnchecked(hash, entry.Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
201-
BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey));
202-
delete pblocktemplate;
214+
mempool.addUnchecked(hash, entry.Fee(1000000).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
215+
BOOST_CHECK_THROW(CreateNewBlock(chainparams, scriptPubKey), std::runtime_error);
203216
mempool.clear();
204217

205-
// double spend txn pair in mempool
218+
// double spend txn pair in mempool, template creation fails
206219
tx.vin[0].prevout.hash = txFirst[0]->GetHash();
207220
tx.vin[0].scriptSig = CScript() << OP_1;
208221
tx.vout[0].nValue = 4900000000LL;
209222
tx.vout[0].scriptPubKey = CScript() << OP_1;
210223
hash = tx.GetHash();
211-
mempool.addUnchecked(hash, entry.Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
224+
mempool.addUnchecked(hash, entry.Fee(100000000L).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
212225
tx.vout[0].scriptPubKey = CScript() << OP_2;
213226
hash = tx.GetHash();
214-
mempool.addUnchecked(hash, entry.Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
215-
BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey));
216-
delete pblocktemplate;
227+
mempool.addUnchecked(hash, entry.Fee(100000000L).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
228+
BOOST_CHECK_THROW(CreateNewBlock(chainparams, scriptPubKey), std::runtime_error);
217229
mempool.clear();
218230

219231
// subsidy changing
@@ -237,7 +249,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
237249
tx.vout[0].scriptPubKey = CScript() << OP_1;
238250
tx.nLockTime = chainActive.Tip()->nHeight+1;
239251
hash = tx.GetHash();
240-
mempool.addUnchecked(hash, entry.Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
252+
mempool.addUnchecked(hash, entry.Fee(100000000L).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
241253
BOOST_CHECK(!CheckFinalTx(tx, LOCKTIME_MEDIAN_TIME_PAST));
242254

243255
// time locked
@@ -251,7 +263,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
251263
tx2.vout[0].scriptPubKey = CScript() << OP_1;
252264
tx2.nLockTime = chainActive.Tip()->GetMedianTimePast()+1;
253265
hash = tx2.GetHash();
254-
mempool.addUnchecked(hash, entry.Time(GetTime()).SpendsCoinbase(true).FromTx(tx2));
266+
mempool.addUnchecked(hash, entry.Fee(100000000L).Time(GetTime()).SpendsCoinbase(true).FromTx(tx2));
255267
BOOST_CHECK(!CheckFinalTx(tx2, LOCKTIME_MEDIAN_TIME_PAST));
256268

257269
BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey));

src/test/test_bitcoin.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(CMutableTransaction &tx, CTxMemPo
150150
CAmount inChainValue = hasNoDependencies ? txn.GetValueOut() : 0;
151151

152152
return CTxMemPoolEntry(txn, nFee, nTime, dPriority, nHeight,
153-
hasNoDependencies, inChainValue, spendsCoinbase);
153+
hasNoDependencies, inChainValue, spendsCoinbase, sigOpCount);
154154
}
155155

156156
void Shutdown(void* parg)

src/test/test_bitcoin.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,12 @@ struct TestMemPoolEntryHelper
6666
unsigned int nHeight;
6767
bool hadNoDependencies;
6868
bool spendsCoinbase;
69-
69+
unsigned int sigOpCount;
70+
7071
TestMemPoolEntryHelper() :
7172
nFee(0), nTime(0), dPriority(0.0), nHeight(1),
72-
hadNoDependencies(false), spendsCoinbase(false) { }
73-
73+
hadNoDependencies(false), spendsCoinbase(false), sigOpCount(1) { }
74+
7475
CTxMemPoolEntry FromTx(CMutableTransaction &tx, CTxMemPool *pool = NULL);
7576

7677
// Change the default value
@@ -80,5 +81,6 @@ struct TestMemPoolEntryHelper
8081
TestMemPoolEntryHelper &Height(unsigned int _height) { nHeight = _height; return *this; }
8182
TestMemPoolEntryHelper &HadNoDependencies(bool _hnd) { hadNoDependencies = _hnd; return *this; }
8283
TestMemPoolEntryHelper &SpendsCoinbase(bool _flag) { spendsCoinbase = _flag; return *this; }
84+
TestMemPoolEntryHelper &SigOps(unsigned int _sigops) { sigOpCount = _sigops; return *this; }
8385
};
8486
#endif

0 commit comments

Comments
 (0)