1 // Copyright (c) 2014-2020 Daniel Kraft
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 <names/main.h>
6 
7 #include <chainparams.h>
8 #include <coins.h>
9 #include <consensus/validation.h>
10 #include <dbwrapper.h>
11 #include <hash.h>
12 #include <names/encoding.h>
13 #include <script/interpreter.h>
14 #include <script/names.h>
15 #include <txmempool.h>
16 #include <uint256.h>
17 #include <undo.h>
18 #include <util/system.h>
19 #include <util/strencodings.h>
20 #include <validation.h>
21 
22 #include <string>
23 #include <vector>
24 
25 namespace
26 {
27 
28 /**
29  * Check whether a name at nPrevHeight is expired at nHeight.  Also
30  * heights of MEMPOOL_HEIGHT are supported.  For nHeight == MEMPOOL_HEIGHT,
31  * we check at the current best tip's height.
32  * @param nPrevHeight The name's output.
33  * @param nHeight The height at which it should be updated.
34  * @return True iff the name is expired.
35  */
36 bool
isExpired(unsigned nPrevHeight,unsigned nHeight)37 isExpired (unsigned nPrevHeight, unsigned nHeight)
38 {
39   assert (nHeight != MEMPOOL_HEIGHT);
40   if (nPrevHeight == MEMPOOL_HEIGHT)
41     return false;
42 
43   const Consensus::Params& params = Params ().GetConsensus ();
44   return nPrevHeight + params.rules->NameExpirationDepth (nHeight) <= nHeight;
45 }
46 
47 } // anonymous namespace
48 
49 /* ************************************************************************** */
50 /* CNameData.  */
51 
52 bool
isExpired() const53 CNameData::isExpired () const
54 {
55   return isExpired (::ChainActive ().Height ());
56 }
57 
58 bool
isExpired(unsigned h) const59 CNameData::isExpired (unsigned h) const
60 {
61   return ::isExpired (nHeight, h);
62 }
63 
64 /* ************************************************************************** */
65 /* CNameTxUndo.  */
66 
67 void
fromOldState(const valtype & nm,const CCoinsView & view)68 CNameTxUndo::fromOldState (const valtype& nm, const CCoinsView& view)
69 {
70   name = nm;
71   isNew = !view.GetName (name, oldData);
72 }
73 
74 void
apply(CCoinsViewCache & view) const75 CNameTxUndo::apply (CCoinsViewCache& view) const
76 {
77   if (isNew)
78     view.DeleteName (name);
79   else
80     view.SetName (name, oldData, true);
81 }
82 
83 /* ************************************************************************** */
84 
85 bool
CheckNameTransaction(const CTransaction & tx,unsigned nHeight,const CCoinsView & view,TxValidationState & state,unsigned flags)86 CheckNameTransaction (const CTransaction& tx, unsigned nHeight,
87                       const CCoinsView& view,
88                       TxValidationState& state, unsigned flags)
89 {
90   const bool fMempool = (flags & SCRIPT_VERIFY_NAMES_MEMPOOL);
91 
92   /* Ignore historic bugs.  */
93   CChainParams::BugType type;
94   if (Params ().IsHistoricBug (tx.GetHash (), nHeight, type))
95     return true;
96 
97   /* As a first step, try to locate inputs and outputs of the transaction
98      that are name scripts.  At most one input and output should be
99      a name operation.  */
100 
101   int nameIn = -1;
102   CNameScript nameOpIn;
103   Coin coinIn;
104   for (unsigned i = 0; i < tx.vin.size (); ++i)
105     {
106       const COutPoint& prevout = tx.vin[i].prevout;
107       Coin coin;
108       if (!view.GetCoin (prevout, coin))
109         return state.Invalid (TxValidationResult::TX_MISSING_INPUTS,
110                               "bad-txns-inputs-missingorspent",
111                               "Failed to fetch name input coin");
112 
113       const CNameScript op(coin.out.scriptPubKey);
114       if (op.isNameOp ())
115         {
116           if (nameIn != -1)
117             return state.Invalid (TxValidationResult::TX_CONSENSUS,
118                                   "tx-multiple-name-inputs",
119                                   "Multiple name inputs");
120           nameIn = i;
121           nameOpIn = op;
122           coinIn = coin;
123         }
124     }
125 
126   int nameOut = -1;
127   CNameScript nameOpOut;
128   for (unsigned i = 0; i < tx.vout.size (); ++i)
129     {
130       const CNameScript op(tx.vout[i].scriptPubKey);
131       if (op.isNameOp ())
132         {
133           if (nameOut != -1)
134             return state.Invalid (TxValidationResult::TX_CONSENSUS,
135                                   "tx-multiple-name-outputs",
136                                   "Multiple name outputs");
137           nameOut = i;
138           nameOpOut = op;
139         }
140     }
141 
142   /* Check that no name inputs/outputs are present for a non-Namecoin tx.
143      If that's the case, all is fine.  For a Namecoin tx instead, there
144      should be at least an output (for NAME_NEW, no inputs are expected).  */
145 
146   if (!tx.IsNamecoin ())
147     {
148       if (nameIn != -1)
149         return state.Invalid (TxValidationResult::TX_CONSENSUS,
150                               "tx-nonname-with-name-input",
151                               "Non-name transaction has name input");
152       if (nameOut != -1)
153         return state.Invalid (TxValidationResult::TX_CONSENSUS,
154                               "tx-nonname-with-name-output",
155                               "Non-name transaction has name output");
156 
157       return true;
158     }
159 
160   assert (tx.IsNamecoin ());
161   if (nameOut == -1)
162     return state.Invalid (TxValidationResult::TX_CONSENSUS,
163                           "tx-name-without-name-output",
164                           "Name transaction has no name output");
165 
166   /* Reject "greedy names".  */
167   const Consensus::Params& params = Params ().GetConsensus ();
168   if (tx.vout[nameOut].nValue < params.rules->MinNameCoinAmount(nHeight))
169     return state.Invalid (TxValidationResult::TX_CONSENSUS,
170                           "tx-name-greedy",
171                           "Greedy name operation");
172 
173   /* Handle NAME_NEW now, since this is easy and different from the other
174      operations.  */
175 
176   if (nameOpOut.getNameOp () == OP_NAME_NEW)
177     {
178       if (nameIn != -1)
179         return state.Invalid (TxValidationResult::TX_CONSENSUS,
180                               "tx-namenew-with-name-input",
181                               "NAME_NEW with previous name input");
182 
183       if (nameOpOut.getOpHash ().size () != 20)
184         return state.Invalid (TxValidationResult::TX_CONSENSUS,
185                               "tx-namenew-wrong-size",
186                               "NAME_NEW's hash has the wrong size");
187 
188       return true;
189     }
190 
191   /* Now that we have ruled out NAME_NEW, check that we have a previous
192      name input that is being updated.  */
193 
194   assert (nameOpOut.isAnyUpdate ());
195   if (nameIn == -1)
196     return state.Invalid (TxValidationResult::TX_CONSENSUS,
197                           "tx-nameupdate-without-name-input",
198                           "Name update has no previous name input");
199   const valtype& name = nameOpOut.getOpName ();
200 
201   if (name.size () > MAX_NAME_LENGTH)
202     return state.Invalid (TxValidationResult::TX_CONSENSUS,
203                           "tx-name-invalid",
204                           "Invalid name");
205   if (nameOpOut.getOpValue ().size () > MAX_VALUE_LENGTH)
206     return state.Invalid (TxValidationResult::TX_CONSENSUS,
207                           "tx-value-invalid",
208                           "Invalid value");
209 
210   /* Process NAME_UPDATE next.  */
211 
212   if (nameOpOut.getNameOp () == OP_NAME_UPDATE)
213     {
214       if (!nameOpIn.isAnyUpdate ())
215         return state.Invalid (TxValidationResult::TX_CONSENSUS,
216                               "tx-nameupdate-invalid-prev",
217                               "Name input for NAME_UPDATE is not an update");
218 
219       if (name != nameOpIn.getOpName ())
220         return state.Invalid (TxValidationResult::TX_CONSENSUS,
221                               "tx-nameupdate-name-mismatch",
222                               "NAME_UPDATE name mismatch to name input");
223 
224       /* If the name input is pending, then no further checks with respect
225          to the name input in the name database are done.  Otherwise, we verify
226          that the name input matches the name database; this is redundant
227          as UTXO handling takes care of it anyway, but we do it for
228          an extra safety layer.  */
229       const unsigned inHeight = coinIn.nHeight;
230       if (inHeight == MEMPOOL_HEIGHT)
231         return true;
232 
233       CNameData oldName;
234       if (!view.GetName (name, oldName))
235         return state.Invalid (TxValidationResult::TX_CONSENSUS,
236                               "tx-nameupdate-nonexistant",
237                               "NAME_UPDATE name does not exist");
238       if (oldName.isExpired (nHeight))
239         return state.Invalid (TxValidationResult::TX_CONSENSUS,
240                               "tx-nameupdate-expired",
241                               "NAME_UPDATE on an expired name");
242       assert (inHeight == oldName.getHeight ());
243       assert (tx.vin[nameIn].prevout == oldName.getUpdateOutpoint ());
244 
245       return true;
246     }
247 
248   /* Finally, NAME_FIRSTUPDATE.  */
249 
250   assert (nameOpOut.getNameOp () == OP_NAME_FIRSTUPDATE);
251   if (nameOpIn.getNameOp () != OP_NAME_NEW)
252     return state.Invalid (TxValidationResult::TX_CONSENSUS,
253                           "tx-firstupdate-nonnew-input",
254                           "NAME_FIRSTUPDATE input is not a NAME_NEW");
255 
256   /* Maturity of NAME_NEW is checked only if we're not adding
257      to the mempool.  */
258   if (!fMempool)
259     {
260       assert (static_cast<unsigned> (coinIn.nHeight) != MEMPOOL_HEIGHT);
261       if (coinIn.nHeight + MIN_FIRSTUPDATE_DEPTH > nHeight)
262         return state.Invalid (TxValidationResult::TX_PREMATURE_SPEND,
263                               "tx-firstupdate-immature",
264                               "NAME_FIRSTUPDATE on immature NAME_NEW");
265     }
266 
267   if (nameOpOut.getOpRand ().size () > 20)
268     return state.Invalid (TxValidationResult::TX_CONSENSUS,
269                           "tx-firstupdate-invalid-rand",
270                           "NAME_FIRSTUPDATE rand value is too large");
271 
272   {
273     valtype toHash(nameOpOut.getOpRand ());
274     toHash.insert (toHash.end (), name.begin (), name.end ());
275     const uint160 hash = Hash160 (toHash);
276     if (hash != uint160 (nameOpIn.getOpHash ()))
277       return state.Invalid (TxValidationResult::TX_CONSENSUS,
278                             "tx-firstupdate-hash-mismatch",
279                             "NAME_FIRSTUPDATE mismatch in hash / rand value");
280   }
281 
282   CNameData oldName;
283   if (view.GetName (name, oldName) && !oldName.isExpired (nHeight))
284     return state.Invalid (TxValidationResult::TX_CONSENSUS,
285                           "tx-firstupdate-existing-name",
286                           "NAME_FIRSTUPDATE on existing name");
287 
288   /* We don't have to specifically check that miners don't create blocks with
289      conflicting NAME_FIRSTUPDATE's, since the mining's CCoinsViewCache
290      takes care of this with the check above already.  */
291 
292   return true;
293 }
294 
295 void
ApplyNameTransaction(const CTransaction & tx,unsigned nHeight,CCoinsViewCache & view,CBlockUndo & undo)296 ApplyNameTransaction (const CTransaction& tx, unsigned nHeight,
297                       CCoinsViewCache& view, CBlockUndo& undo)
298 {
299   assert (nHeight != MEMPOOL_HEIGHT);
300 
301   /* Handle historic bugs that should *not* be applied.  Names that are
302      outputs should be marked as unspendable in this case.  Otherwise,
303      we get an inconsistency between the UTXO set and the name database.  */
304   CChainParams::BugType type;
305   const uint256 txHash = tx.GetHash ();
306   if (Params ().IsHistoricBug (txHash, nHeight, type)
307       && type != CChainParams::BUG_FULLY_APPLY)
308     {
309       if (type == CChainParams::BUG_FULLY_IGNORE)
310         for (unsigned i = 0; i < tx.vout.size (); ++i)
311           {
312             const CNameScript op(tx.vout[i].scriptPubKey);
313             if (op.isNameOp () && op.isAnyUpdate ())
314               view.SpendCoin (COutPoint (txHash, i));
315           }
316       return;
317     }
318 
319   /* This check must be done *after* the historic bug fixing above!  Some
320      of the names that must be handled above are actually produced by
321      transactions *not* marked as Namecoin tx.  */
322   if (!tx.IsNamecoin ())
323     return;
324 
325   /* Changes are encoded in the outputs.  We don't have to do any checks,
326      so simply apply all these.  */
327 
328   for (unsigned i = 0; i < tx.vout.size (); ++i)
329     {
330       const CNameScript op(tx.vout[i].scriptPubKey);
331       if (op.isNameOp () && op.isAnyUpdate ())
332         {
333           const valtype& name = op.getOpName ();
334           LogPrint (BCLog::NAMES, "Updating name at height %d: %s\n",
335                     nHeight, EncodeNameForMessage (name));
336 
337           CNameTxUndo opUndo;
338           opUndo.fromOldState (name, view);
339           undo.vnameundo.push_back (opUndo);
340 
341           CNameData data;
342           data.fromScript (nHeight, COutPoint (tx.GetHash (), i), op);
343           view.SetName (name, data, false);
344         }
345     }
346 }
347 
348 bool
ExpireNames(unsigned nHeight,CCoinsViewCache & view,CBlockUndo & undo,std::set<valtype> & names)349 ExpireNames (unsigned nHeight, CCoinsViewCache& view, CBlockUndo& undo,
350              std::set<valtype>& names)
351 {
352   names.clear ();
353 
354   /* The genesis block contains no name expirations.  */
355   if (nHeight == 0)
356     return true;
357 
358   /* Otherwise, find out at which update heights names have expired
359      since the last block.  If the expiration depth changes, this could
360      be multiple heights at once.  */
361 
362   const Consensus::Params& params = Params ().GetConsensus ();
363   const unsigned expDepthOld = params.rules->NameExpirationDepth (nHeight - 1);
364   const unsigned expDepthNow = params.rules->NameExpirationDepth (nHeight);
365 
366   if (expDepthNow > nHeight)
367     return true;
368 
369   /* Both are inclusive!  The last expireTo was nHeight - 1 - expDepthOld,
370      now we start at this value + 1.  */
371   const unsigned expireFrom = nHeight - expDepthOld;
372   const unsigned expireTo = nHeight - expDepthNow;
373 
374   /* It is possible that expireFrom = expireTo + 1, in case that the
375      expiration period is raised together with the block height.  In this
376      case, no names expire in the current step.  This case means that
377      the absolute expiration height "n - expirationDepth(n)" is
378      flat -- which is fine.  */
379   assert (expireFrom <= expireTo + 1);
380 
381   /* Find all names that expire at those depths.  Note that GetNamesForHeight
382      clears the output set, to we union all sets here.  */
383   for (unsigned h = expireFrom; h <= expireTo; ++h)
384     {
385       std::set<valtype> newNames;
386       view.GetNamesForHeight (h, newNames);
387       names.insert (newNames.begin (), newNames.end ());
388     }
389 
390   /* Expire all those names.  */
391   for (std::set<valtype>::const_iterator i = names.begin ();
392        i != names.end (); ++i)
393     {
394       const std::string nameStr = EncodeNameForMessage (*i);
395 
396       CNameData data;
397       if (!view.GetName (*i, data))
398         return error ("%s : name %s not found in the database",
399                       __func__, nameStr);
400       if (!data.isExpired (nHeight))
401         return error ("%s : name %s is not actually expired",
402                       __func__, nameStr);
403 
404       /* Special rule:  When d/postmortem expires (the name used by
405          libcoin in the name-stealing demonstration), it's coin
406          is already spent.  Ignore.  */
407       if (nHeight == 175868
408             && EncodeName (*i, NameEncoding::ASCII) == "d/postmortem")
409         continue;
410 
411       const COutPoint& out = data.getUpdateOutpoint ();
412       Coin coin;
413       if (!view.GetCoin(out, coin))
414         return error ("%s : name coin for %s is not available",
415                       __func__, nameStr);
416       const CNameScript nameOp(coin.out.scriptPubKey);
417       if (!nameOp.isNameOp () || !nameOp.isAnyUpdate ()
418           || nameOp.getOpName () != *i)
419         return error ("%s : name coin to be expired is wrong script", __func__);
420 
421       if (!view.SpendCoin (out, &coin))
422         return error ("%s : spending name coin failed", __func__);
423       undo.vexpired.push_back (coin);
424     }
425 
426   return true;
427 }
428 
429 bool
UnexpireNames(unsigned nHeight,CBlockUndo & undo,CCoinsViewCache & view,std::set<valtype> & names)430 UnexpireNames (unsigned nHeight, CBlockUndo& undo, CCoinsViewCache& view,
431                std::set<valtype>& names)
432 {
433   names.clear ();
434 
435   /* The genesis block contains no name expirations.  */
436   if (nHeight == 0)
437     return true;
438 
439   std::vector<Coin>::reverse_iterator i;
440   for (i = undo.vexpired.rbegin (); i != undo.vexpired.rend (); ++i)
441     {
442       const CNameScript nameOp(i->out.scriptPubKey);
443       if (!nameOp.isNameOp () || !nameOp.isAnyUpdate ())
444         return error ("%s : wrong script to be unexpired", __func__);
445 
446       const valtype& name = nameOp.getOpName ();
447       if (names.count (name) > 0)
448         return error ("%s : name %s unexpired twice",
449                       __func__, EncodeNameForMessage (name));
450       names.insert (name);
451 
452       CNameData data;
453       if (!view.GetName (nameOp.getOpName (), data))
454         return error ("%s : no data for name '%s' to be unexpired",
455                       __func__, EncodeNameForMessage (name));
456       if (!data.isExpired (nHeight) || data.isExpired (nHeight - 1))
457         return error ("%s : name '%s' to be unexpired is not expired in the DB"
458                       " or it was already expired before the current height",
459                       __func__, EncodeNameForMessage (name));
460 
461       if (ApplyTxInUndo (std::move(*i), view,
462                          data.getUpdateOutpoint ()) != DISCONNECT_OK)
463         return error ("%s : failed to undo name coin spending", __func__);
464     }
465 
466   return true;
467 }
468 
469 void
CheckNameDB(ChainstateManager & chainman,bool disconnect)470 CheckNameDB (ChainstateManager& chainman, bool disconnect)
471 {
472   const int option
473     = gArgs.GetArg ("-checknamedb", Params ().DefaultCheckNameDB ());
474 
475   if (option == -1)
476     return;
477 
478   assert (option >= 0);
479   if (option != 0)
480     {
481       if (disconnect || chainman.ActiveChain ().Height () % option != 0)
482         return;
483     }
484 
485   auto& coinsTip = chainman.ActiveChainstate ().CoinsTip ();
486   coinsTip.Flush ();
487   const bool ok = coinsTip.ValidateNameDB (chainman, [] () {});
488 
489   /* The DB is inconsistent (mismatch between UTXO set and names DB) between
490      (roughly) blocks 139,000 and 180,000.  This is caused by libcoin's
491      "name stealing" bug.  For instance, d/postmortem is removed from
492      the UTXO set shortly after registration (when it is used to steal
493      names), but it remains in the name DB until it expires.  */
494   if (!ok)
495     {
496       const unsigned nHeight = ::ChainActive ().Height ();
497       LogPrintf ("ERROR: %s : name database is inconsistent\n", __func__);
498       if (nHeight >= 139000 && nHeight <= 180000)
499         LogPrintf ("This is expected due to 'name stealing'.\n");
500       else
501         assert (false);
502     }
503 }
504