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 <script/names.h>
6 
7 #include <hash.h>
8 #include <uint256.h>
9 
CNameScript(const CScript & script)10 CNameScript::CNameScript (const CScript& script)
11   : op(OP_NOP), address(script)
12 {
13   opcodetype nameOp;
14   CScript::const_iterator pc = script.begin ();
15   if (!script.GetOp (pc, nameOp))
16     return;
17 
18   opcodetype opcode;
19   while (true)
20     {
21       valtype vch;
22 
23       if (!script.GetOp (pc, opcode, vch))
24         return;
25       if (opcode == OP_DROP || opcode == OP_2DROP || opcode == OP_NOP)
26         break;
27       if (!(opcode >= 0 && opcode <= OP_PUSHDATA4))
28         return;
29 
30       args.push_back (vch);
31     }
32 
33   // Move the pc to after any DROP or NOP.
34   while (opcode == OP_DROP || opcode == OP_2DROP || opcode == OP_NOP)
35     if (!script.GetOp (pc, opcode))
36       break;
37   pc--;
38 
39   /* Now, we have the args and the operation.  Check if we have indeed
40      a valid name operation and valid argument counts.  Only now set the
41      op and address members, if everything is valid.  */
42   switch (nameOp)
43     {
44     case OP_NAME_NEW:
45       if (args.size () != 1)
46         return;
47       break;
48 
49     case OP_NAME_FIRSTUPDATE:
50       if (args.size () != 3)
51         return;
52       break;
53 
54     case OP_NAME_UPDATE:
55       if (args.size () != 2)
56         return;
57       break;
58 
59     default:
60       return;
61     }
62 
63   op = nameOp;
64   address = CScript (pc, script.end ());
65 }
66 
67 namespace
68 {
69 
70 /**
71  * Concats together a base address and name prefix script.
72  */
73 CScript
AddNamePrefix(const CScript & addr,const CScript & prefix)74 AddNamePrefix (const CScript& addr, const CScript& prefix)
75 {
76   CScript res = prefix;
77   res.insert (res.end (), addr.begin (), addr.end ());
78   return res;
79 }
80 
81 } // anonymous namespace
82 
83 CScript
buildNameNew(const CScript & addr,const valtype & name,const valtype & rand)84 CNameScript::buildNameNew (const CScript& addr, const valtype& name,
85                            const valtype& rand)
86 {
87   valtype toHash(rand);
88   toHash.insert (toHash.end (), name.begin (), name.end ());
89   const uint160 hash = Hash160 (toHash);
90 
91   CScript prefix;
92   prefix << OP_NAME_NEW << ToByteVector (hash) << OP_2DROP;
93 
94   return AddNamePrefix (addr, prefix);
95 }
96 
97 CScript
buildNameFirstupdate(const CScript & addr,const valtype & name,const valtype & value,const valtype & rand)98 CNameScript::buildNameFirstupdate (const CScript& addr, const valtype& name,
99                                    const valtype& value, const valtype& rand)
100 {
101   CScript prefix;
102   prefix << OP_NAME_FIRSTUPDATE << name << rand << value
103          << OP_2DROP << OP_2DROP;
104 
105   return AddNamePrefix (addr, prefix);
106 }
107 
108 CScript
buildNameUpdate(const CScript & addr,const valtype & name,const valtype & value)109 CNameScript::buildNameUpdate (const CScript& addr, const valtype& name,
110                               const valtype& value)
111 {
112   CScript prefix;
113   prefix << OP_NAME_UPDATE << name << value << OP_2DROP << OP_DROP;
114 
115   return AddNamePrefix (addr, prefix);
116 }
117