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