Skip to content

Commit 2be9b53

Browse files
committed
Unit test for mempool with UTXO hasher.
This extends the mempool unit tests to explicitly verify that adding transactions, removing transactions, checking the pool and looking up coins / transactions still works even if we use the bare txid for some transactions as UTXO hash (as will be the case with segwit-light in the future).
1 parent 0af523d commit 2be9b53

File tree

5 files changed

+103
-16
lines changed

5 files changed

+103
-16
lines changed

divi/src/test/MockUtxoHasher.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ uint256 MockUtxoHasher::Add(const CTransaction& tx)
1111
return value;
1212
}
1313

14+
void MockUtxoHasher::UseBareTxid(const CTransaction& tx)
15+
{
16+
customHashes.emplace(tx.GetHash(), tx.GetBareTxid());
17+
}
18+
1419
uint256 MockUtxoHasher::GetUtxoHash(const CTransaction& tx) const
1520
{
1621
const uint256 txid = tx.GetHash();

divi/src/test/MockUtxoHasher.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ class MockUtxoHasher : public TransactionUtxoHasher
3232
* is generated uniquely and returned from the function. */
3333
uint256 Add(const CTransaction& tx);
3434

35+
/** Marks the given transaction for using the bare txid rather than
36+
* the normal txid. */
37+
void UseBareTxid(const CTransaction& tx);
38+
3539
uint256 GetUtxoHash(const CTransaction& tx) const override;
3640

3741
};

divi/src/test/mempool_tests.cpp

Lines changed: 85 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,36 +2,67 @@
22
// Distributed under the MIT software license, see the accompanying
33
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
44

5-
#include "main.h"
65
#include "txmempool.h"
76

7+
#include "blockmap.h"
8+
#include "MockUtxoHasher.h"
9+
810
#include <boost/test/unit_test.hpp>
911
#include <list>
1012

13+
extern CChain chainActive;
14+
extern BlockMap mapBlockIndex;
15+
1116
class MempoolTestFixture
1217
{
1318

19+
private:
20+
21+
/** Empty coins view used to back the cached view we actually use. */
22+
CCoinsView emptyView;
23+
24+
/** Tip of our fake chain. */
25+
CBlockIndex tip;
26+
1427
protected:
1528

1629
/** A parent transaction. */
1730
CMutableTransaction txParent;
1831

19-
/** Three children of the parent. */
32+
/** Three children of the parent. They use the bare txid for their UTXOs
33+
* in our UTXO hasher. */
2034
CMutableTransaction txChild[3];
2135

2236
/** Three grand children. */
2337
CMutableTransaction txGrandChild[3];
2438

39+
/** Coins view with the parent inputs. */
40+
CCoinsViewCache view;
41+
2542
/** The test mempool instance. */
2643
CTxMemPool testPool;
2744

2845
public:
2946

3047
MempoolTestFixture()
31-
: testPool(CFeeRate(0))
48+
: view(&emptyView), testPool(CFeeRate(0))
3249
{
50+
std::unique_ptr<MockUtxoHasher> utxoHasher(new MockUtxoHasher());
51+
52+
CMutableTransaction base;
53+
base.vout.emplace_back(99000LL, CScript() << OP_11 << OP_EQUAL);
54+
view.ModifyCoins(base.GetHash())->FromTx(base, 0);
55+
56+
tip.pprev = nullptr;
57+
tip.nHeight = 0;
58+
mapBlockIndex[tip.GetBlockHeader().GetHash()] = &tip;
59+
view.SetBestBlock(tip.GetBlockHeader().GetHash());
60+
chainActive.SetTip(&tip);
61+
3362
txParent.vin.resize(1);
3463
txParent.vin[0].scriptSig = CScript() << OP_11;
64+
txParent.vin[0].prevout.hash = base.GetHash();
65+
txParent.vin[0].prevout.n = 0;
3566
txParent.vout.resize(3);
3667
for (int i = 0; i < 3; i++)
3768
{
@@ -48,18 +79,39 @@ class MempoolTestFixture
4879
txChild[i].vout.resize(1);
4980
txChild[i].vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
5081
txChild[i].vout[0].nValue = 11000LL;
82+
utxoHasher->UseBareTxid(txChild[i]);
5183
}
5284

5385
for (int i = 0; i < 3; i++)
5486
{
5587
txGrandChild[i].vin.resize(1);
5688
txGrandChild[i].vin[0].scriptSig = CScript() << OP_11;
57-
txGrandChild[i].vin[0].prevout.hash = txChild[i].GetHash();
89+
txGrandChild[i].vin[0].prevout.hash = txChild[i].GetBareTxid();
5890
txGrandChild[i].vin[0].prevout.n = 0;
5991
txGrandChild[i].vout.resize(1);
6092
txGrandChild[i].vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
6193
txGrandChild[i].vout[0].nValue = 11000LL;
6294
}
95+
96+
testPool.setSanityCheck(true);
97+
testPool.SetUtxoHasherForTesting(std::move(utxoHasher));
98+
testPool.clear();
99+
}
100+
101+
~MempoolTestFixture()
102+
{
103+
mapBlockIndex.clear();
104+
}
105+
106+
/** Adds the parent, childs and grandchilds to the mempool. */
107+
void AddAll()
108+
{
109+
testPool.addUnchecked(txParent.GetHash(), CTxMemPoolEntry(txParent, 0, 0, 0.0, 1));
110+
for (int i = 0; i < 3; i++)
111+
{
112+
testPool.addUnchecked(txChild[i].GetHash(), CTxMemPoolEntry(txChild[i], 0, 0, 0.0, 1));
113+
testPool.addUnchecked(txGrandChild[i].GetHash(), CTxMemPoolEntry(txGrandChild[i], 0, 0, 0.0, 1));
114+
}
63115
}
64116

65117
};
@@ -83,12 +135,10 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest)
83135
removed.clear();
84136

85137
// Parent, children, grandchildren:
86-
testPool.addUnchecked(txParent.GetHash(), CTxMemPoolEntry(txParent, 0, 0, 0.0, 1));
87-
for (int i = 0; i < 3; i++)
88-
{
89-
testPool.addUnchecked(txChild[i].GetHash(), CTxMemPoolEntry(txChild[i], 0, 0, 0.0, 1));
90-
testPool.addUnchecked(txGrandChild[i].GetHash(), CTxMemPoolEntry(txGrandChild[i], 0, 0, 0.0, 1));
91-
}
138+
AddAll();
139+
140+
testPool.check(&view);
141+
92142
// Remove Child[0], GrandChild[0] should be removed:
93143
testPool.remove(txChild[0], removed, true);
94144
BOOST_CHECK_EQUAL(removed.size(), 2);
@@ -123,12 +173,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexByBareTxid)
123173
CTransaction tx;
124174
std::list<CTransaction> removed;
125175

126-
testPool.addUnchecked(txParent.GetHash(), CTxMemPoolEntry(txParent, 0, 0, 0.0, 1));
127-
for (int i = 0; i < 3; ++i)
128-
{
129-
testPool.addUnchecked(txChild[i].GetHash(), CTxMemPoolEntry(txChild[i], 0, 0, 0.0, 1));
130-
testPool.addUnchecked(txGrandChild[i].GetHash(), CTxMemPoolEntry(txGrandChild[i], 0, 0, 0.0, 1));
131-
}
176+
AddAll();
132177

133178
BOOST_CHECK(testPool.lookupBareTxid(txParent.GetBareTxid(), tx));
134179
BOOST_CHECK(tx.GetHash() == txParent.GetHash());
@@ -140,4 +185,28 @@ BOOST_AUTO_TEST_CASE(MempoolIndexByBareTxid)
140185
BOOST_CHECK(!testPool.lookupBareTxid(txGrandChild[0].GetBareTxid(), tx));
141186
}
142187

188+
BOOST_AUTO_TEST_CASE(MempoolOutpointLookup)
189+
{
190+
CTransaction tx;
191+
CCoins coins;
192+
193+
AddAll();
194+
CCoinsViewMemPool viewPool(&view, testPool);
195+
196+
BOOST_CHECK(testPool.lookupOutpoint(txParent.GetHash(), tx));
197+
BOOST_CHECK(!testPool.lookupOutpoint(txParent.GetBareTxid(), tx));
198+
BOOST_CHECK(!testPool.lookupOutpoint(txChild[0].GetHash(), tx));
199+
BOOST_CHECK(testPool.lookupOutpoint(txChild[0].GetBareTxid(), tx));
200+
201+
BOOST_CHECK(viewPool.HaveCoins(txParent.GetHash()));
202+
BOOST_CHECK(viewPool.GetCoins(txParent.GetHash(), coins));
203+
BOOST_CHECK(!viewPool.HaveCoins(txParent.GetBareTxid()));
204+
BOOST_CHECK(!viewPool.GetCoins(txParent.GetBareTxid(), coins));
205+
206+
BOOST_CHECK(!viewPool.HaveCoins(txChild[0].GetHash()));
207+
BOOST_CHECK(!viewPool.GetCoins(txChild[0].GetHash(), coins));
208+
BOOST_CHECK(viewPool.HaveCoins(txChild[0].GetBareTxid()));
209+
BOOST_CHECK(viewPool.GetCoins(txChild[0].GetBareTxid(), coins));
210+
}
211+
143212
BOOST_AUTO_TEST_SUITE_END()

divi/src/txmempool.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,11 @@ const TransactionUtxoHasher& CTxMemPool::GetUtxoHasher() const
450450
return *utxoHasher;
451451
}
452452

453+
void CTxMemPool::SetUtxoHasherForTesting(std::unique_ptr<TransactionUtxoHasher> hasher)
454+
{
455+
utxoHasher = std::move(hasher);
456+
}
457+
453458
void CTxMemPool::addAddressIndex(const CTxMemPoolEntry &entry, const CCoinsViewCache &view)
454459
{
455460
LOCK(cs);

divi/src/txmempool.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,10 @@ class CTxMemPool
158158
/** Returns the UTXO hasher instance used in the mempool. */
159159
const TransactionUtxoHasher& GetUtxoHasher() const;
160160

161+
/** Replaces the UTXO hasher used in the mempool with the given instance,
162+
* which allows dependency injection for unit tests. */
163+
void SetUtxoHasherForTesting(std::unique_ptr<TransactionUtxoHasher> hasher);
164+
161165
void addAddressIndex(const CTxMemPoolEntry &entry, const CCoinsViewCache &view);
162166
bool getAddressIndex(std::vector<std::pair<uint160, int> > &addresses,
163167
std::vector<std::pair<CMempoolAddressDeltaKey, CMempoolAddressDelta> > &results);

0 commit comments

Comments
 (0)