PIVX Core  5.6.99
P2P Digital Currency
policyestimator_tests.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2015 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #include "policy/feerate.h"
6 #include "policy/fees.h"
7 #include "txmempool.h"
8 #include "uint256.h"
9 #include "util/system.h"
10 
11 #include "test/test_pivx.h"
12 
13 #include <boost/test/unit_test.hpp>
14 
15 BOOST_FIXTURE_TEST_SUITE(policyestimator_tests, TestingSetup)
16 
17 BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
18 {
19  CTxMemPool mpool(CFeeRate(1000));
21  CAmount basefee(2000);
22  CAmount deltaFee(100);
23  std::vector<CAmount> feeV;
24 
25  // Populate vectors of increasing fees
26  for (int j = 0; j < 10; j++) {
27  feeV.push_back(basefee * (j+1));
28  }
29 
30  // Store the hashes of transactions that have been
31  // added to the mempool by their associate fee
32  // txHashes[j] is populated with transactions either of
33  // fee = basefee * (j+1)
34  std::vector<uint256> txHashes[10];
35 
36  // Create a transaction template
37  CScript garbage;
38  for (unsigned int i = 0; i < 128; i++)
39  garbage.push_back('X');
41  tx.vin.resize(1);
42  tx.vin[0].scriptSig = garbage;
43  tx.vout.resize(1);
44  tx.vout[0].nValue=0LL;
45  CFeeRate baseRate(basefee, ::GetSerializeSize(tx, PROTOCOL_VERSION));
46 
47  // Create a fake block
48  std::vector<CTransactionRef> block;
49  int blocknum = 0;
50 
51  // Loop through 200 blocks
52  // At a decay .998 and 4 fee transactions per block
53  // This makes the tx count about 1.33 per bucket, above the 1 threshold
54  while (blocknum < 200) {
55  for (int j = 0; j < 10; j++) { // For each fee
56  for (int k = 0; k < 4; k++) { // add 4 fee txs
57  tx.vin[0].prevout.n = 10000*blocknum+100*j+k; // make transaction unique
58  uint256 hash = tx.GetHash();
59  mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx));
60  txHashes[j].push_back(hash);
61  }
62  }
63  //Create blocks where higher fee txs are included more often
64  for (int h = 0; h <= blocknum%10; h++) {
65  // 10/10 blocks add highest fee transactions
66  // 9/10 blocks add 2nd highest and so on until ...
67  // 1/10 blocks add lowest fee transactions
68  while (txHashes[9-h].size()) {
69  CTransactionRef ptx = mpool.get(txHashes[9-h].back());
70  if (ptx)
71  block.emplace_back(ptx);
72  txHashes[9-h].pop_back();
73  }
74  }
75  mpool.removeForBlock(block, ++blocknum);
76  block.clear();
77  if (blocknum == 30) {
78  // At this point we should need to combine 5 buckets to get enough data points
79  // So estimateFee(1,2,3) should fail and estimateFee(4) should return somewhere around
80  // 8*baserate. estimateFee(4) %'s are 100,100,100,100,90 = average 98%
81  BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(0));
82  BOOST_CHECK(mpool.estimateFee(2) == CFeeRate(0));
83  BOOST_CHECK(mpool.estimateFee(3) == CFeeRate(0));
84  BOOST_CHECK(mpool.estimateFee(4).GetFeePerK() < 8*baseRate.GetFeePerK() + deltaFee);
85  BOOST_CHECK(mpool.estimateFee(4).GetFeePerK() > 8*baseRate.GetFeePerK() - deltaFee);
86  int answerFound;
87  BOOST_CHECK(mpool.estimateSmartFee(1, &answerFound) == mpool.estimateFee(4) && answerFound == 4);
88  BOOST_CHECK(mpool.estimateSmartFee(3, &answerFound) == mpool.estimateFee(4) && answerFound == 4);
89  BOOST_CHECK(mpool.estimateSmartFee(4, &answerFound) == mpool.estimateFee(4) && answerFound == 4);
90  BOOST_CHECK(mpool.estimateSmartFee(8, &answerFound) == mpool.estimateFee(8) && answerFound == 8);
91  }
92  }
93 
94  std::vector<CAmount> origFeeEst;
95  // Highest feerate is 10*baseRate and gets in all blocks,
96  // second highest feerate is 9*baseRate and gets in 9/10 blocks = 90%,
97  // third highest feerate is 8*base rate, and gets in 8/10 blocks = 80%,
98  // so estimateFee(1) should return 10*baseRate.
99  // Second highest feerate has 100% chance of being included by 2 blocks,
100  // so estimateFee(2) should return 9*baseRate etc...
101  for (int i = 1; i < 10;i++) {
102  origFeeEst.push_back(mpool.estimateFee(i).GetFeePerK());
103  if (i > 1) { // Fee estimates should be monotonically decreasing
104  BOOST_CHECK(origFeeEst[i-1] <= origFeeEst[i-2]);
105  }
106  int mult = 11-i;
107  BOOST_CHECK(origFeeEst[i-1] < mult*baseRate.GetFeePerK() + deltaFee);
108  BOOST_CHECK(origFeeEst[i-1] > mult*baseRate.GetFeePerK() - deltaFee);
109  }
110 
111  // Mine 50 more blocks with no transactions happening, estimates shouldn't change
112  // We haven't decayed the moving average enough so we still have enough data points in every bucket
113  while (blocknum < 250)
114  mpool.removeForBlock(block, ++blocknum);
115 
116  for (int i = 1; i < 10;i++) {
117  BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() < origFeeEst[i-1] + deltaFee);
118  BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
119  }
120 
121 
122  // Mine 15 more blocks with lots of transactions happening and not getting mined
123  // Estimates should go up
124  while (blocknum < 265) {
125  for (int j = 0; j < 10; j++) { // For each fee multiple
126  for (int k = 0; k < 4; k++) { // add 4 fee txs
127  tx.vin[0].prevout.n = 10000*blocknum+100*j+k;
128  uint256 hash = tx.GetHash();
129  mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx));
130  txHashes[j].push_back(hash);
131  }
132  }
133  mpool.removeForBlock(block, ++blocknum);
134  }
135 
136  int answerFound;
137  for (int i = 1; i < 10;i++) {
138  BOOST_CHECK(mpool.estimateFee(i) == CFeeRate(0) || mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
139  BOOST_CHECK(mpool.estimateSmartFee(i, &answerFound).GetFeePerK() > origFeeEst[answerFound-1] - deltaFee);
140  }
141 
142  // Mine all those transactions
143  // Estimates should still not be below original
144  for (int j = 0; j < 10; j++) {
145  while(txHashes[j].size()) {
146  CTransactionRef ptx = mpool.get(txHashes[j].back());
147  if (ptx)
148  block.emplace_back(ptx);
149  txHashes[j].pop_back();
150  }
151  }
152  mpool.removeForBlock(block, 265);
153  block.clear();
154  for (int i = 1; i < 10;i++) {
155  BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
156  }
157 
158  // Mine 200 more blocks where everything is mined every block
159  // Estimates should be below original estimates
160  while (blocknum < 465) {
161  for (int j = 0; j < 10; j++) { // For each fee multiple
162  for (int k = 0; k < 4; k++) { // add 4 fee txs
163  tx.vin[0].prevout.n = 10000*blocknum+100*j+k;
164  uint256 hash = tx.GetHash();
165  mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx));
166  CTransactionRef ptx = mpool.get(hash);
167  if (ptx)
168  block.emplace_back(ptx);
169  }
170  }
171  mpool.removeForBlock(block, ++blocknum);
172  block.clear();
173  }
174  for (int i = 1; i < 10; i++) {
175  BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() < origFeeEst[i-1] - deltaFee);
176  }
177 
178  // Test that if the mempool is limited, estimateSmartFee won't return a value below the mempool min fee
179  mpool.addUnchecked(tx.GetHash(), entry.Fee(feeV[5]).Time(GetTime()).Height(blocknum).FromTx(tx));
180  // evict that transaction which should set a mempool min fee of minRelayTxFee + feeV[5]
181  mpool.TrimToSize(1);
182  BOOST_CHECK(mpool.GetMinFee(1).GetFeePerK() > feeV[5]);
183  for (int i = 1; i < 10; i++) {
185  BOOST_CHECK(mpool.estimateSmartFee(i).GetFeePerK() >= mpool.GetMinFee(1).GetFeePerK());
186  }
187 }
188 
int64_t CAmount
Amount in PIV (Can be negative)
Definition: amount.h:13
Fee rate in PIV per kilobyte: CAmount / kB.
Definition: feerate.h:20
CAmount GetFeePerK() const
Definition: feerate.h:29
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:381
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
Definition: txmempool.h:384
CFeeRate GetMinFee(size_t sizelimit) const
The minimum fee to get into the mempool, which may itself not be enough for larger-sized transactions...
Definition: txmempool.cpp:1412
CTransactionRef get(const uint256 &hash) const
Definition: txmempool.cpp:1128
CFeeRate estimateFee(int nBlocks) const
Estimate fee rate needed to get into the next nBlocks.
Definition: txmempool.cpp:1200
CFeeRate estimateSmartFee(int nBlocks, int *answerFoundAtBlocks=nullptr) const
Estimate fee rate needed to get into the next nBlocks If no answer can be given at nBlocks,...
Definition: txmempool.cpp:1206
bool addUnchecked(const uint256 &hash, const CTxMemPoolEntry &entry, bool validFeeEstimate=true)
Definition: txmempool.cpp:1366
void TrimToSize(size_t sizelimit, std::vector< COutPoint > *pvNoSpendsRemaining=nullptr)
Remove transactions from the mempool until its dynamic size is <= sizelimit.
Definition: txmempool.cpp:1446
void removeForBlock(const std::vector< CTransactionRef > &vtx, unsigned int nBlockHeight)
Called when a block is connected.
Definition: txmempool.cpp:844
void push_back(const T &value)
Definition: prevector.h:435
256-bit opaque blob.
Definition: uint256.h:138
BOOST_AUTO_TEST_SUITE_END()
#define BOOST_FIXTURE_TEST_SUITE(a, b)
Definition: object.cpp:14
#define BOOST_CHECK(expr)
Definition: object.cpp:17
BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
unsigned int GetSerializeSize(const std::array< T, N > &item)
array
Definition: serialize.h:847
A mutable version of CTransaction.
Definition: transaction.h:409
uint256 GetHash() const
Compute the hash of this CMutableTransaction.
Definition: transaction.cpp:96
std::vector< CTxOut > vout
Definition: transaction.h:411
std::vector< CTxIn > vin
Definition: transaction.h:410
Definition: test_pivx.h:137
TestMemPoolEntryHelper & Time(int64_t _time)
Definition: test_pivx.h:154
TestMemPoolEntryHelper & Fee(CAmount _fee)
Definition: test_pivx.h:153
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:456
int64_t GetTime()
DEPRECATED Use either GetSystemTimeInSeconds (not mockable) or GetTime<T> (mockable)
Definition: utiltime.cpp:27