1 // Copyright (c) 2014-2019 Daniel Kraft
2 // Distributed under the MIT/X11 software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #include <base58.h>
6 #include <coins.h>
7 #include <key_io.h>
8 #include <names/encoding.h>
9 #include <names/mempool.h>
10 #include <primitives/transaction.h>
11 #include <script/names.h>
12 #include <sync.h>
13 #include <txmempool.h>
14 #include <validation.h>
15 #include <validationinterface.h>
16 
17 #include <test/util/setup_common.h>
18 
19 #include <boost/test/unit_test.hpp>
20 
21 /* No space between BOOST_FIXTURE_TEST_SUITE and '(', so that extraction of
22    the test-suite name works with grep as done in the Makefile.  */
23 BOOST_AUTO_TEST_SUITE(name_mempool_tests)
24 
25 namespace
26 {
27 
28 class NameMempoolTestSetup : public TestingSetup
29 {
30 
31 public:
32 
33   CTxMemPool mempool;
34 
35   CScript ADDR;
36   CScript OTHER_ADDR;
37 
38   const LockPoints lp;
39 
NameMempoolTestSetup()40   NameMempoolTestSetup ()
41   {
42     ADDR = CScript () << OP_TRUE;
43     OTHER_ADDR = CScript () << OP_TRUE << OP_RETURN;
44 
45     ENTER_CRITICAL_SECTION (mempool.cs);
46   }
47 
~NameMempoolTestSetup()48   ~NameMempoolTestSetup ()
49   {
50     LEAVE_CRITICAL_SECTION (mempool.cs);
51   }
52 
53   /**
54    * Returns a valtype name based on the given string.
55    */
56   static valtype
Name(const std::string & str)57   Name (const std::string& str)
58   {
59     return DecodeName (str, NameEncoding::ASCII);
60   }
61 
62   /**
63    * Returns the hash bytes for a name_new.
64    */
65   static valtype
NewHash(const std::string & nm,const char rand)66   NewHash (const std::string& nm, const char rand)
67   {
68     const valtype nameVal = Name (nm);
69     const valtype randVal(20, rand);
70 
71     valtype toHash(randVal);
72     toHash.insert (toHash.end (), nameVal.begin (), nameVal.end ());
73     const uint160 hash = Hash160 (toHash);
74 
75     return valtype (hash.begin (), hash.end ());
76   }
77 
78   /**
79    * Builds a name new script for the given test name and rand based
80    * on a character (just to allow different rand's).
81    */
82   static CScript
NewScript(const CScript & addr,const std::string & nm,const char rand)83   NewScript (const CScript& addr, const std::string& nm, const char rand)
84   {
85     const valtype randVal(20, rand);
86 
87     return CNameScript::buildNameNew (addr, Name (nm), randVal);
88   }
89 
90   /**
91    * Builds a name_firstupdate script for the given name and rand value.
92    * The value we update to is just a fixed one.
93    */
94   static CScript
FirstScript(const CScript & addr,const std::string & nm,const char rand)95   FirstScript (const CScript& addr, const std::string& nm, const char rand)
96   {
97     const valtype randVal(20, rand);
98     const valtype value = DecodeName ("firstupdate value", NameEncoding::ASCII);
99 
100     return CNameScript::buildNameFirstupdate (addr, Name (nm), value, randVal);
101   }
102 
103   /**
104    * Builds a name_update script based on the given name and value.
105    */
106   static CScript
UpdateScript(const CScript & addr,const std::string & nm,const std::string & val)107   UpdateScript (const CScript& addr, const std::string& nm,
108                 const std::string& val)
109   {
110     const valtype value = DecodeName (val, NameEncoding::ASCII);
111 
112     return CNameScript::buildNameUpdate (addr, Name (nm), value);
113   }
114 
115   /**
116    * Builds a transaction spending to a name-output script.  The transaction
117    * is not valid, but it is "valid enough" for testing the name mempool
118    * rules with it.
119    */
120   static CTransaction
Tx(const CScript & out)121   Tx (const CScript& out)
122   {
123     CMutableTransaction mtx;
124     mtx.SetNamecoin ();
125     mtx.vout.push_back (CTxOut (COIN, out));
126 
127     return CTransaction (mtx);
128   }
129 
130   /**
131    * Builds a mempool entry for the given transaction.
132    */
133   CTxMemPoolEntry
Entry(const CTransaction & tx)134   Entry (const CTransaction& tx)
135   {
136     return CTxMemPoolEntry (MakeTransactionRef (tx), 0, 0, 100, false, 1, lp);
137   }
138 
139 };
140 
141 } // anonymous namespace
142 
143 /* ************************************************************************** */
144 
BOOST_FIXTURE_TEST_CASE(invalid_tx,NameMempoolTestSetup)145 BOOST_FIXTURE_TEST_CASE (invalid_tx, NameMempoolTestSetup)
146 {
147   /* Invalid transactions should not crash / assert fail the mempool check.  */
148 
149   CMutableTransaction mtx;
150   mtx.SetNamecoin ();
151   mempool.checkNameOps (CTransaction (mtx));
152 
153   mtx.vout.push_back (CTxOut (COIN, NewScript (ADDR, "foo", 'a')));
154   mtx.vout.push_back (CTxOut (COIN, NewScript (ADDR, "bar", 'b')));
155   mtx.vout.push_back (CTxOut (COIN, FirstScript (ADDR, "foo", 'a')));
156   mtx.vout.push_back (CTxOut (COIN, FirstScript (ADDR, "bar", 'b')));
157   mtx.vout.push_back (CTxOut (COIN, UpdateScript (ADDR, "foo", "x")));
158   mtx.vout.push_back (CTxOut (COIN, UpdateScript (ADDR, "bar", "y")));
159   mempool.checkNameOps (CTransaction (mtx));
160 }
161 
BOOST_FIXTURE_TEST_CASE(empty_mempool,NameMempoolTestSetup)162 BOOST_FIXTURE_TEST_CASE (empty_mempool, NameMempoolTestSetup)
163 {
164   /* While the mempool is empty (we do not add any transactions in this test),
165      all should be fine without respect to conflicts among the transactions.  */
166 
167   BOOST_CHECK (!mempool.registersName (Name ("foo")));
168   BOOST_CHECK (!mempool.updatesName (Name ("foo")));
169 
170   BOOST_CHECK (mempool.checkNameOps (Tx (NewScript (ADDR, "foo", 'a'))));
171   BOOST_CHECK (mempool.checkNameOps (Tx (NewScript (ADDR, "foo", 'b'))));
172   BOOST_CHECK (mempool.checkNameOps (Tx (NewScript (OTHER_ADDR, "foo", 'a'))));
173 
174   BOOST_CHECK (mempool.checkNameOps (Tx (FirstScript (ADDR, "foo", 'a'))));
175   BOOST_CHECK (mempool.checkNameOps (Tx (FirstScript (ADDR, "foo", 'b'))));
176 
177   BOOST_CHECK (mempool.checkNameOps (Tx (UpdateScript (ADDR, "foo", "x"))));
178   BOOST_CHECK (mempool.checkNameOps (Tx (UpdateScript (ADDR, "foo", "y"))));
179 }
180 
BOOST_FIXTURE_TEST_CASE(pendingChainLength_lastNameOutput,NameMempoolTestSetup)181 BOOST_FIXTURE_TEST_CASE (pendingChainLength_lastNameOutput,
182                          NameMempoolTestSetup)
183 {
184   const auto txNew = Tx (NewScript (ADDR, "new", 'a'));
185   const auto txReg = Tx (FirstScript (ADDR, "reg", 'b'));
186   const auto txUpd = Tx (UpdateScript (ADDR, "upd", "x"));
187 
188   mempool.addUnchecked (Entry (txNew));
189   mempool.addUnchecked (Entry (txReg));
190   mempool.addUnchecked (Entry (txUpd));
191 
192   /* For testing chained name updates, we have to build a "real" chain of
193      transactions with matching inputs and outputs.  */
194 
195   CMutableTransaction mtx;
196   mtx.SetNamecoin ();
197   mtx.vout.push_back (CTxOut (COIN, FirstScript (ADDR, "chain", 'a')));
198   mtx.vout.push_back (CTxOut (COIN, ADDR));
199   mtx.vout.push_back (CTxOut (COIN, OTHER_ADDR));
200   const CTransaction chain1(mtx);
201   mempool.addUnchecked (Entry (chain1));
202 
203   mtx.vout.clear ();
204   mtx.vout.push_back (CTxOut (COIN, ADDR));
205   mtx.vout.push_back (CTxOut (COIN, UpdateScript (ADDR, "chain", "x")));
206   mtx.vin.push_back (CTxIn (COutPoint (chain1.GetHash (), 0)));
207   const CTransaction chain2(mtx);
208   mempool.addUnchecked (Entry (chain2));
209 
210   mtx.vout.clear ();
211   mtx.vout.push_back (CTxOut (COIN, OTHER_ADDR));
212   mtx.vout.push_back (CTxOut (COIN, UpdateScript (ADDR, "chain", "y")));
213   mtx.vin.push_back (CTxIn (COutPoint (chain2.GetHash (), 0)));
214   mtx.vin.push_back (CTxIn (COutPoint (chain1.GetHash (), 1)));
215   const CTransaction chain3(mtx);
216   mempool.addUnchecked (Entry (chain3));
217 
218   CMutableTransaction mtxCurrency;
219   mtxCurrency.vin.push_back (CTxIn (COutPoint (chain1.GetHash (), 2)));
220   mtxCurrency.vin.push_back (CTxIn (COutPoint (chain3.GetHash (), 0)));
221   mempool.addUnchecked (Entry (CTransaction (mtxCurrency)));
222 
223   BOOST_CHECK (mempool.lastNameOutput (Name ("new")).IsNull ());
224   BOOST_CHECK (mempool.lastNameOutput (Name ("reg"))
225                   == COutPoint (txReg.GetHash (), 0));
226   BOOST_CHECK (mempool.lastNameOutput (Name ("upd"))
227                   == COutPoint (txUpd.GetHash (), 0));
228   BOOST_CHECK (mempool.lastNameOutput (Name ("chain"))
229                   == COutPoint (chain3.GetHash (), 1));
230 
231   BOOST_CHECK_EQUAL (mempool.pendingNameChainLength (Name ("new")), 0);
232   BOOST_CHECK_EQUAL (mempool.pendingNameChainLength (Name ("reg")), 1);
233   BOOST_CHECK_EQUAL (mempool.pendingNameChainLength (Name ("upd")), 1);
234   BOOST_CHECK_EQUAL (mempool.pendingNameChainLength (Name ("chain")), 3);
235 }
236 
BOOST_FIXTURE_TEST_CASE(name_new,NameMempoolTestSetup)237 BOOST_FIXTURE_TEST_CASE (name_new, NameMempoolTestSetup)
238 {
239   const auto tx1 = Tx (NewScript (ADDR, "foo", 'a'));
240   const auto tx1p = Tx (NewScript (OTHER_ADDR, "foo", 'a'));
241   const auto tx2 = Tx (NewScript (ADDR, "foo", 'b'));
242 
243   const auto e1 = Entry (tx1);
244   const auto e2 = Entry (tx2);
245   BOOST_CHECK (e1.isNameNew () && e2.isNameNew ());
246   BOOST_CHECK (e1.getNameNewHash () == NewHash ("foo", 'a'));
247   BOOST_CHECK (e2.getNameNewHash () == NewHash ("foo", 'b'));
248 
249   mempool.addUnchecked (e1);
250   mempool.addUnchecked (e2);
251   BOOST_CHECK (mempool.checkNameOps (tx1));
252   BOOST_CHECK (mempool.checkNameOps (tx2));
253   BOOST_CHECK (!mempool.checkNameOps (tx1p));
254 
255   mempool.removeRecursive (tx1, MemPoolRemovalReason::EXPIRY);
256   mempool.removeRecursive (tx2, MemPoolRemovalReason::EXPIRY);
257   BOOST_CHECK (mempool.checkNameOps (tx1));
258   BOOST_CHECK (mempool.checkNameOps (tx2));
259   BOOST_CHECK (!mempool.checkNameOps (tx1p));
260 }
261 
BOOST_FIXTURE_TEST_CASE(name_firstupdate,NameMempoolTestSetup)262 BOOST_FIXTURE_TEST_CASE (name_firstupdate, NameMempoolTestSetup)
263 {
264   const auto tx1 = Tx (FirstScript (ADDR, "foo", 'a'));
265   const auto tx2 = Tx (FirstScript (ADDR, "foo", 'b'));
266 
267   const auto e = Entry (tx1);
268   BOOST_CHECK (e.isNameRegistration () && !e.isNameUpdate ());
269   BOOST_CHECK (e.getName () == Name ("foo"));
270 
271   mempool.addUnchecked (e);
272   BOOST_CHECK (mempool.registersName (Name ("foo")));
273   BOOST_CHECK (!mempool.updatesName (Name ("foo")));
274   BOOST_CHECK (!mempool.checkNameOps (tx2));
275 
276   mempool.removeRecursive (tx1, MemPoolRemovalReason::EXPIRY);
277   BOOST_CHECK (!mempool.registersName (Name ("foo")));
278   BOOST_CHECK (mempool.checkNameOps (tx1));
279   BOOST_CHECK (mempool.checkNameOps (tx2));
280 }
281 
BOOST_FIXTURE_TEST_CASE(name_update,NameMempoolTestSetup)282 BOOST_FIXTURE_TEST_CASE (name_update, NameMempoolTestSetup)
283 {
284   const auto tx1 = Tx (UpdateScript (ADDR, "foo", "x"));
285   const auto tx2 = Tx (UpdateScript (ADDR, "foo", "y"));
286   const auto tx3 = Tx (UpdateScript (ADDR, "bar", "z"));
287 
288   const auto e1 = Entry (tx1);
289   const auto e2 = Entry (tx2);
290   const auto e3 = Entry (tx3);
291   BOOST_CHECK (!e1.isNameRegistration () && e1.isNameUpdate ());
292   BOOST_CHECK (e1.getName () == Name ("foo"));
293 
294   mempool.addUnchecked (e1);
295   mempool.addUnchecked (e2);
296   mempool.addUnchecked (e3);
297   BOOST_CHECK (!mempool.registersName (Name ("foo")));
298   BOOST_CHECK (mempool.updatesName (Name ("foo")));
299   BOOST_CHECK (mempool.updatesName (Name ("bar")));
300 
301   mempool.removeRecursive (tx2, MemPoolRemovalReason::EXPIRY);
302   BOOST_CHECK (mempool.updatesName (Name ("foo")));
303   BOOST_CHECK (mempool.updatesName (Name ("bar")));
304 
305   mempool.removeRecursive (tx1, MemPoolRemovalReason::EXPIRY);
306   BOOST_CHECK (!mempool.updatesName (Name ("foo")));
307   BOOST_CHECK (mempool.updatesName (Name ("bar")));
308 
309   mempool.removeRecursive (tx3, MemPoolRemovalReason::EXPIRY);
310   BOOST_CHECK (!mempool.updatesName (Name ("foo")));
311   BOOST_CHECK (!mempool.updatesName (Name ("bar")));
312 }
313 
BOOST_FIXTURE_TEST_CASE(mempool_sanity_check,NameMempoolTestSetup)314 BOOST_FIXTURE_TEST_CASE (mempool_sanity_check, NameMempoolTestSetup)
315 {
316   mempool.addUnchecked (Entry (Tx (NewScript (ADDR, "new", 'a'))));
317   mempool.addUnchecked (Entry (Tx (NewScript (ADDR, "new", 'b'))));
318 
319   mempool.addUnchecked (Entry (Tx (FirstScript (ADDR, "reg", 'a'))));
320   mempool.addUnchecked (Entry (Tx (UpdateScript (ADDR, "reg", "n"))));
321 
322   mempool.addUnchecked (Entry (Tx (UpdateScript (ADDR, "upd", "x"))));
323   mempool.addUnchecked (Entry (Tx (UpdateScript (ADDR, "upd", "y"))));
324 
325   ChainstateManager& chainman = g_chainman;
326   CCoinsViewCache view(&chainman.ActiveChainstate ().CoinsTip ());
327 
328   const CNameScript nameOp(UpdateScript (ADDR, "upd", "o"));
329   CNameData data;
330   data.fromScript (100, COutPoint (uint256 (), 0), nameOp);
331   view.SetName (Name ("upd"), data, false);
332 
333   mempool.checkNames (chainman, &view);
334 }
335 
336 namespace
337 {
338 
339 /**
340  * Helper class that listens to TransactionRemovedFromMempool and records
341  * the txid's of all transactions removed.
342  */
343 class NameConflictTracker : public CValidationInterface
344 {
345 
346 private:
347 
348   /** The txids that have been removed according to our callback.  */
349   std::vector<uint256> txids;
350 
351 public:
352 
NameConflictTracker()353   NameConflictTracker ()
354   {
355     RegisterValidationInterface (this);
356   }
357 
~NameConflictTracker()358   ~NameConflictTracker ()
359   {
360     UnregisterValidationInterface (this);
361   }
362 
363   void
TransactionRemovedFromMempool(const CTransactionRef & ptxn,const MemPoolRemovalReason reason,const uint64_t sequence)364   TransactionRemovedFromMempool (const CTransactionRef& ptxn,
365                                  const MemPoolRemovalReason reason,
366                                  const uint64_t sequence) override
367   {
368     txids.push_back (ptxn->GetHash ());
369   }
370 
371   /**
372    * Expects the given list of txids to be removed.  Waits for all outstanding
373    * callbacks to be processed as needed.
374    */
375   void
ExpectTxids(const std::vector<uint256> & expected) const376   ExpectTxids (const std::vector<uint256>& expected) const
377   {
378     while (GetMainSignals ().CallbacksPending () > 0)
379       UninterruptibleSleep (std::chrono::milliseconds (10));
380     BOOST_CHECK (txids == expected);
381   }
382 
383 };
384 
385 } // anonymous namespace
386 
BOOST_FIXTURE_TEST_CASE(registration_conflicts,NameMempoolTestSetup)387 BOOST_FIXTURE_TEST_CASE (registration_conflicts, NameMempoolTestSetup)
388 {
389   const auto tx1 = Tx (FirstScript (ADDR, "foo", 'a'));
390   const auto tx2 = Tx (FirstScript (ADDR, "foo", 'b'));
391   const auto e = Entry (tx1);
392 
393   mempool.addUnchecked (e);
394   BOOST_CHECK (mempool.registersName (Name ("foo")));
395   BOOST_CHECK (!mempool.checkNameOps (tx2));
396 
397   NameConflictTracker tracker;
398   mempool.removeConflicts (tx2);
399   tracker.ExpectTxids ({tx1.GetHash ()});
400 
401   BOOST_CHECK (!mempool.registersName (Name ("foo")));
402   BOOST_CHECK (mempool.checkNameOps (tx1));
403   BOOST_CHECK (mempool.checkNameOps (tx2));
404   BOOST_CHECK (mempool.mapTx.empty ());
405 }
406 
BOOST_FIXTURE_TEST_CASE(expire_conflicts,NameMempoolTestSetup)407 BOOST_FIXTURE_TEST_CASE (expire_conflicts, NameMempoolTestSetup)
408 {
409   const auto tx1 = Tx (UpdateScript (ADDR, "foo", "x"));
410   const auto tx2 = Tx (UpdateScript (ADDR, "foo", "y"));
411   const auto e1 = Entry (tx1);
412   const auto e2 = Entry (tx2);
413 
414   mempool.addUnchecked (e1);
415   mempool.addUnchecked (e2);
416   BOOST_CHECK (mempool.updatesName (Name ("foo")));
417 
418   NameConflictTracker tracker;
419   mempool.removeExpireConflicts ({Name ("foo")});
420   tracker.ExpectTxids ({tx1.GetHash (), tx2.GetHash ()});
421 
422   BOOST_CHECK (!mempool.updatesName (Name ("foo")));
423   BOOST_CHECK (mempool.mapTx.empty ());
424 }
425 
BOOST_FIXTURE_TEST_CASE(unexpire_conflicts,NameMempoolTestSetup)426 BOOST_FIXTURE_TEST_CASE (unexpire_conflicts, NameMempoolTestSetup)
427 {
428   const auto tx = Tx (FirstScript (ADDR, "foo", 'a'));
429   const auto e = Entry (tx);
430 
431   mempool.addUnchecked (e);
432   BOOST_CHECK (mempool.registersName (Name ("foo")));
433 
434   NameConflictTracker tracker;
435   mempool.removeUnexpireConflicts ({Name ("foo")});
436   tracker.ExpectTxids ({tx.GetHash ()});
437 
438   BOOST_CHECK (!mempool.registersName (Name ("foo")));
439   BOOST_CHECK (mempool.mapTx.empty ());
440 }
441 
442 /* ************************************************************************** */
443 
444 BOOST_AUTO_TEST_SUITE_END ()
445