27
27
28
28
#include < boost/thread.hpp>
29
29
#include < boost/tuple/tuple.hpp>
30
+ #include < queue>
30
31
31
32
using namespace std ;
32
33
@@ -40,48 +41,18 @@ using namespace std;
40
41
// transactions in the memory pool. When we select transactions from the
41
42
// pool, we select by highest priority or fee rate, so we might consider
42
43
// transactions that depend on transactions that aren't yet in the block.
43
- // The COrphan class keeps track of these 'temporary orphans' while
44
- // CreateBlock is figuring out which transactions to include.
45
- //
46
- class COrphan
47
- {
48
- public:
49
- const CTransaction* ptx;
50
- set<uint256> setDependsOn;
51
- CFeeRate feeRate;
52
- double dPriority;
53
-
54
- COrphan (const CTransaction* ptxIn) : ptx(ptxIn), feeRate(0 ), dPriority(0 )
55
- {
56
- }
57
- };
58
44
59
45
uint64_t nLastBlockTx = 0 ;
60
46
uint64_t nLastBlockSize = 0 ;
61
47
62
- // We want to sort transactions by priority and fee rate, so:
63
- typedef boost::tuple<double , CFeeRate, const CTransaction*> TxPriority;
64
- class TxPriorityCompare
48
+ class ScoreCompare
65
49
{
66
- bool byFee;
67
-
68
50
public:
69
- TxPriorityCompare ( bool _byFee) : byFee(_byFee) { }
51
+ ScoreCompare () { }
70
52
71
- bool operator ()(const TxPriority& a, const TxPriority& b)
53
+ bool operator ()(const CTxMemPool::txiter a, const CTxMemPool::txiter b)
72
54
{
73
- if (byFee)
74
- {
75
- if (a.get <1 >() == b.get <1 >())
76
- return a.get <0 >() < b.get <0 >();
77
- return a.get <1 >() < b.get <1 >();
78
- }
79
- else
80
- {
81
- if (a.get <0 >() == b.get <0 >())
82
- return a.get <1 >() < b.get <1 >();
83
- return a.get <0 >() < b.get <0 >();
84
- }
55
+ return CompareTxMemPoolEntryByScore ()(*b,*a); // Convert to less than
85
56
}
86
57
};
87
58
@@ -141,6 +112,22 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s
141
112
nBlockMinSize = std::min (nBlockMaxSize, nBlockMinSize);
142
113
143
114
// Collect memory pool transactions into the block
115
+ CTxMemPool::setEntries inBlock;
116
+ CTxMemPool::setEntries waitSet;
117
+
118
+ // This vector will be sorted into a priority queue:
119
+ vector<TxCoinAgePriority> vecPriority;
120
+ TxCoinAgePriorityCompare pricomparer;
121
+ std::map<CTxMemPool::txiter, double , CTxMemPool::CompareIteratorByHash> waitPriMap;
122
+ typedef std::map<CTxMemPool::txiter, double , CTxMemPool::CompareIteratorByHash>::iterator waitPriIter;
123
+ double actualPriority = -1 ;
124
+
125
+ std::priority_queue<CTxMemPool::txiter, std::vector<CTxMemPool::txiter>, ScoreCompare> clearedTxs;
126
+ bool fPrintPriority = GetBoolArg (" -printpriority" , DEFAULT_PRINTPRIORITY);
127
+ uint64_t nBlockSize = 1000 ;
128
+ uint64_t nBlockTx = 0 ;
129
+ unsigned int nBlockSigOps = 100 ;
130
+ int lastFewTxs = 0 ;
144
131
CAmount nFees = 0 ;
145
132
146
133
{
@@ -149,157 +136,102 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s
149
136
const int nHeight = pindexPrev->nHeight + 1 ;
150
137
pblock->nTime = GetAdjustedTime ();
151
138
const int64_t nMedianTimePast = pindexPrev->GetMedianTimePast ();
152
- CCoinsViewCache view (pcoinsTip);
153
-
154
- // Priority order to process transactions
155
- list<COrphan> vOrphan; // list memory doesn't move
156
- map<uint256, vector<COrphan*> > mapDependers;
157
- bool fPrintPriority = GetBoolArg (" -printpriority" , DEFAULT_PRINTPRIORITY);
158
-
159
- // This vector will be sorted into a priority queue:
160
- vector<TxPriority> vecPriority;
161
- vecPriority.reserve (mempool.mapTx .size ());
162
- for (CTxMemPool::indexed_transaction_set::iterator mi = mempool.mapTx .begin ();
163
- mi != mempool.mapTx .end (); ++mi)
164
- {
165
- const CTransaction& tx = mi->GetTx ();
166
-
167
- int64_t nLockTimeCutoff = (STANDARD_LOCKTIME_VERIFY_FLAGS & LOCKTIME_MEDIAN_TIME_PAST)
168
- ? nMedianTimePast
169
- : pblock->GetBlockTime ();
170
-
171
- if (tx.IsCoinBase () || !IsFinalTx (tx, nHeight, nLockTimeCutoff))
172
- continue ;
173
-
174
- COrphan* porphan = NULL ;
175
- double dPriority = 0 ;
176
- CAmount nTotalIn = 0 ;
177
- bool fMissingInputs = false ;
178
- BOOST_FOREACH (const CTxIn& txin, tx.vin )
179
- {
180
- // Read prev transaction
181
- if (!view.HaveCoins (txin.prevout .hash ))
182
- {
183
- // This should never happen; all transactions in the memory
184
- // pool should connect to either transactions in the chain
185
- // or other transactions in the memory pool.
186
- if (!mempool.mapTx .count (txin.prevout .hash ))
187
- {
188
- LogPrintf (" ERROR: mempool transaction missing input\n " );
189
- if (fDebug ) assert (" mempool transaction missing input" == 0 );
190
- fMissingInputs = true ;
191
- if (porphan)
192
- vOrphan.pop_back ();
193
- break ;
194
- }
195
-
196
- // Has to wait for dependencies
197
- if (!porphan)
198
- {
199
- // Use list for automatic deletion
200
- vOrphan.push_back (COrphan (&tx));
201
- porphan = &vOrphan.back ();
202
- }
203
- mapDependers[txin.prevout .hash ].push_back (porphan);
204
- porphan->setDependsOn .insert (txin.prevout .hash );
205
- nTotalIn += mempool.mapTx .find (txin.prevout .hash )->GetTx ().vout [txin.prevout .n ].nValue ;
206
- continue ;
207
- }
208
- const CCoins* coins = view.AccessCoins (txin.prevout .hash );
209
- assert (coins);
210
-
211
- CAmount nValueIn = coins->vout [txin.prevout .n ].nValue ;
212
- nTotalIn += nValueIn;
213
-
214
- int nConf = nHeight - coins->nHeight ;
215
-
216
- dPriority += (double )nValueIn * nConf;
217
- }
218
- if (fMissingInputs ) continue ;
219
-
220
- // Priority is sum(valuein * age) / modified_txsize
221
- unsigned int nTxSize = ::GetSerializeSize (tx, SER_NETWORK, PROTOCOL_VERSION);
222
- dPriority = tx.ComputePriority (dPriority, nTxSize);
223
-
224
- uint256 hash = tx.GetHash ();
225
- mempool.ApplyDeltas (hash, dPriority, nTotalIn);
226
139
227
- CFeeRate feeRate (nTotalIn-tx.GetValueOut (), nTxSize);
140
+ int64_t nLockTimeCutoff = (STANDARD_LOCKTIME_VERIFY_FLAGS & LOCKTIME_MEDIAN_TIME_PAST)
141
+ ? nMedianTimePast
142
+ : pblock->GetBlockTime ();
228
143
229
- if (porphan)
144
+ bool fPriorityBlock = nBlockPrioritySize > 0 ;
145
+ if (fPriorityBlock ) {
146
+ vecPriority.reserve (mempool.mapTx .size ());
147
+ for (CTxMemPool::indexed_transaction_set::iterator mi = mempool.mapTx .begin ();
148
+ mi != mempool.mapTx .end (); ++mi)
230
149
{
231
- porphan->dPriority = dPriority;
232
- porphan->feeRate = feeRate;
150
+ double dPriority = mi->GetPriority (nHeight);
151
+ CAmount dummy;
152
+ mempool.ApplyDeltas (mi->GetTx ().GetHash (), dPriority, dummy);
153
+ vecPriority.push_back (TxCoinAgePriority (dPriority, mi));
233
154
}
234
- else
235
- vecPriority.push_back (TxPriority (dPriority, feeRate, &(mi->GetTx ())));
155
+ std::make_heap (vecPriority.begin (), vecPriority.end (), pricomparer);
236
156
}
237
157
238
- // Collect transactions into block
239
- uint64_t nBlockSize = 1000 ;
240
- uint64_t nBlockTx = 0 ;
241
- int nBlockSigOps = 100 ;
242
- bool fSortedByFee = (nBlockPrioritySize <= 0 );
158
+ CTxMemPool::indexed_transaction_set::nth_index<3 >::type::iterator mi = mempool.mapTx .get <3 >().begin ();
159
+ CTxMemPool::txiter iter;
243
160
244
- TxPriorityCompare comparer (fSortedByFee );
245
- std::make_heap (vecPriority.begin (), vecPriority.end (), comparer);
246
-
247
- while (!vecPriority.empty ())
161
+ while (mi != mempool.mapTx .get <3 >().end () || !clearedTxs.empty ())
248
162
{
249
- // Take highest priority transaction off the priority queue:
250
- double dPriority = vecPriority.front ().get <0 >();
251
- CFeeRate feeRate = vecPriority.front ().get <1 >();
252
- const CTransaction& tx = *(vecPriority.front ().get <2 >());
253
-
254
- std::pop_heap (vecPriority.begin (), vecPriority.end (), comparer);
255
- vecPriority.pop_back ();
256
-
257
- // Size limits
258
- unsigned int nTxSize = ::GetSerializeSize (tx, SER_NETWORK, PROTOCOL_VERSION);
259
- if (nBlockSize + nTxSize >= nBlockMaxSize)
260
- continue ;
163
+ bool priorityTx = false ;
164
+ if (fPriorityBlock && !vecPriority.empty ()) { // add a tx from priority queue to fill the blockprioritysize
165
+ priorityTx = true ;
166
+ iter = vecPriority.front ().second ;
167
+ actualPriority = vecPriority.front ().first ;
168
+ std::pop_heap (vecPriority.begin (), vecPriority.end (), pricomparer);
169
+ vecPriority.pop_back ();
170
+ }
171
+ else if (clearedTxs.empty ()) { // add tx with next highest score
172
+ iter = mempool.mapTx .project <0 >(mi);
173
+ mi++;
174
+ }
175
+ else { // try to add a previously postponed child tx
176
+ iter = clearedTxs.top ();
177
+ clearedTxs.pop ();
178
+ }
261
179
262
- // Legacy limits on sigOps:
263
- unsigned int nTxSigOps = GetLegacySigOpCount (tx);
264
- if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)
265
- continue ;
180
+ if (inBlock.count (iter))
181
+ continue ; // could have been added to the priorityBlock
266
182
267
- // Skip free transactions if we're past the minimum block size:
268
- const uint256& hash = tx.GetHash ();
269
- double dPriorityDelta = 0 ;
270
- CAmount nFeeDelta = 0 ;
271
- mempool.ApplyDeltas (hash, dPriorityDelta, nFeeDelta);
272
- if (fSortedByFee && (dPriorityDelta <= 0 ) && (nFeeDelta <= 0 ) && (feeRate < ::minRelayTxFee) && (nBlockSize + nTxSize >= nBlockMinSize))
273
- continue ;
183
+ const CTransaction& tx = iter->GetTx ();
274
184
275
- // Prioritise by fee once past the priority size or we run out of high-priority
276
- // transactions:
277
- if (!fSortedByFee &&
278
- ((nBlockSize + nTxSize >= nBlockPrioritySize) || !AllowFree (dPriority)))
185
+ bool fOrphan = false ;
186
+ BOOST_FOREACH (CTxMemPool::txiter parent, mempool.GetMemPoolParents (iter))
279
187
{
280
- fSortedByFee = true ;
281
- comparer = TxPriorityCompare (fSortedByFee );
282
- std::make_heap (vecPriority.begin (), vecPriority.end (), comparer);
188
+ if (!inBlock.count (parent)) {
189
+ fOrphan = true ;
190
+ break ;
191
+ }
283
192
}
284
-
285
- if (!view.HaveInputs (tx))
193
+ if (fOrphan ) {
194
+ if (priorityTx)
195
+ waitPriMap.insert (std::make_pair (iter,actualPriority));
196
+ else
197
+ waitSet.insert (iter);
286
198
continue ;
199
+ }
287
200
288
- CAmount nTxFees = view.GetValueIn (tx)-tx.GetValueOut ();
289
-
290
- nTxSigOps += GetP2SHSigOpCount (tx, view);
291
- if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)
201
+ unsigned int nTxSize = iter->GetTxSize ();
202
+ if (fPriorityBlock &&
203
+ (nBlockSize + nTxSize >= nBlockPrioritySize || !AllowFree (actualPriority))) {
204
+ fPriorityBlock = false ;
205
+ waitPriMap.clear ();
206
+ }
207
+ if (!priorityTx &&
208
+ (iter->GetModifiedFee () < ::minRelayTxFee.GetFee (nTxSize) && nBlockSize >= nBlockMinSize)) {
209
+ break ;
210
+ }
211
+ if (nBlockSize + nTxSize >= nBlockMaxSize) {
212
+ if (nBlockSize > nBlockMaxSize - 100 || lastFewTxs > 50 ) {
213
+ break ;
214
+ }
215
+ // Once we're within 1000 bytes of a full block, only look at 50 more txs
216
+ // to try to fill the remaining space.
217
+ if (nBlockSize > nBlockMaxSize - 1000 ) {
218
+ lastFewTxs++;
219
+ }
292
220
continue ;
221
+ }
293
222
294
- // Note that flags: we don't want to set mempool/IsStandard()
295
- // policy here, but we still have to ensure that the block we
296
- // create only contains transactions that are valid in new blocks.
297
- CValidationState state;
298
- if (!CheckInputs (tx, state, view, true , MANDATORY_SCRIPT_VERIFY_FLAGS, true ))
223
+ if (!IsFinalTx (tx, nHeight, nLockTimeCutoff))
299
224
continue ;
300
225
301
- UpdateCoins (tx, state, view, nHeight);
226
+ unsigned int nTxSigOps = iter->GetSigOpCount ();
227
+ if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) {
228
+ if (nBlockSigOps > MAX_BLOCK_SIGOPS - 2 ) {
229
+ break ;
230
+ }
231
+ continue ;
232
+ }
302
233
234
+ CAmount nTxFees = iter->GetFee ();
303
235
// Added
304
236
pblock->vtx .push_back (tx);
305
237
pblocktemplate->vTxFees .push_back (nTxFees);
@@ -311,31 +243,37 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s
311
243
312
244
if (fPrintPriority )
313
245
{
246
+ double dPriority = iter->GetPriority (nHeight);
247
+ CAmount dummy;
248
+ mempool.ApplyDeltas (tx.GetHash (), dPriority, dummy);
314
249
LogPrintf (" priority %.1f fee %s txid %s\n " ,
315
- dPriority, feeRate .ToString (), tx.GetHash ().ToString ());
250
+ dPriority , CFeeRate (iter-> GetModifiedFee (), nTxSize) .ToString (), tx.GetHash ().ToString ());
316
251
}
317
252
253
+ inBlock.insert (iter);
254
+
318
255
// Add transactions that depend on this one to the priority queue
319
- if (mapDependers. count (hash ))
256
+ BOOST_FOREACH (CTxMemPool::txiter child, mempool. GetMemPoolChildren (iter ))
320
257
{
321
- BOOST_FOREACH (COrphan* porphan, mapDependers[hash])
322
- {
323
- if (!porphan->setDependsOn .empty ())
324
- {
325
- porphan->setDependsOn .erase (hash);
326
- if (porphan->setDependsOn .empty ())
327
- {
328
- vecPriority.push_back (TxPriority (porphan->dPriority , porphan->feeRate , porphan->ptx ));
329
- std::push_heap (vecPriority.begin (), vecPriority.end (), comparer);
330
- }
258
+ if (fPriorityBlock ) {
259
+ waitPriIter wpiter = waitPriMap.find (child);
260
+ if (wpiter != waitPriMap.end ()) {
261
+ vecPriority.push_back (TxCoinAgePriority (wpiter->second ,child));
262
+ std::push_heap (vecPriority.begin (), vecPriority.end (), pricomparer);
263
+ waitPriMap.erase (wpiter);
264
+ }
265
+ }
266
+ else {
267
+ if (waitSet.count (child)) {
268
+ clearedTxs.push (child);
269
+ waitSet.erase (child);
331
270
}
332
271
}
333
272
}
334
273
}
335
-
336
274
nLastBlockTx = nBlockTx;
337
275
nLastBlockSize = nBlockSize;
338
- LogPrintf (" CreateNewBlock(): total size %u\n " , nBlockSize);
276
+ LogPrintf (" CreateNewBlock(): total size %u txs: %u fees: %ld sigops %d \n " , nBlockSize, nBlockTx, nFees, nBlockSigOps );
339
277
340
278
// Compute final coinbase transaction.
341
279
txNew.vout [0 ].nValue = nFees + GetBlockSubsidy (nHeight, chainparams.GetConsensus ());
@@ -351,8 +289,9 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s
351
289
pblocktemplate->vTxSigOps [0 ] = GetLegacySigOpCount (pblock->vtx [0 ]);
352
290
353
291
CValidationState state;
354
- if (!TestBlockValidity (state, chainparams, *pblock, pindexPrev, false , false ))
355
- throw std::runtime_error (" CreateNewBlock(): TestBlockValidity failed" );
292
+ if (!TestBlockValidity (state, chainparams, *pblock, pindexPrev, false , false )) {
293
+ throw std::runtime_error (strprintf (" %s: TestBlockValidity failed: %s" , __func__, FormatStateMessage (state)));
294
+ }
356
295
}
357
296
358
297
return pblocktemplate.release ();
0 commit comments