1 // Copyright (c) 2009-2019 The Bitcoin Core developers
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 <core_io.h>
6 
7 #include <consensus/consensus.h>
8 #include <consensus/validation.h>
9 #include <key_io.h>
10 #include <names/encoding.h>
11 #include <script/names.h>
12 #include <script/script.h>
13 #include <script/standard.h>
14 #include <serialize.h>
15 #include <streams.h>
16 #include <univalue.h>
17 #include <util/system.h>
18 #include <util/strencodings.h>
19 
ValueFromAmount(const CAmount & amount)20 UniValue ValueFromAmount(const CAmount& amount)
21 {
22     bool sign = amount < 0;
23     int64_t n_abs = (sign ? -amount : amount);
24     int64_t quotient = n_abs / COIN;
25     int64_t remainder = n_abs % COIN;
26     return UniValue(UniValue::VNUM,
27             strprintf("%s%d.%08d", sign ? "-" : "", quotient, remainder));
28 }
29 
FormatScript(const CScript & script)30 std::string FormatScript(const CScript& script)
31 {
32     std::string ret;
33     CScript::const_iterator it = script.begin();
34     opcodetype op;
35     while (it != script.end()) {
36         CScript::const_iterator it2 = it;
37         std::vector<unsigned char> vch;
38         if (script.GetOp(it, op, vch)) {
39             if (op == OP_0) {
40                 ret += "0 ";
41                 continue;
42             } else if ((op >= OP_1 && op <= OP_16) || op == OP_1NEGATE) {
43                 ret += strprintf("%i ", op - OP_1NEGATE - 1);
44                 continue;
45             } else if (op >= OP_NOP && op <= OP_NOP10) {
46                 std::string str(GetOpName(op));
47                 if (str.substr(0, 3) == std::string("OP_")) {
48                     ret += str.substr(3, std::string::npos) + " ";
49                     continue;
50                 }
51             }
52             if (vch.size() > 0) {
53                 ret += strprintf("0x%x 0x%x ", HexStr(std::vector<uint8_t>(it2, it - vch.size())),
54                                                HexStr(std::vector<uint8_t>(it - vch.size(), it)));
55             } else {
56                 ret += strprintf("0x%x ", HexStr(std::vector<uint8_t>(it2, it)));
57             }
58             continue;
59         }
60         ret += strprintf("0x%x ", HexStr(std::vector<uint8_t>(it2, script.end())));
61         break;
62     }
63     return ret.substr(0, ret.size() - 1);
64 }
65 
66 const std::map<unsigned char, std::string> mapSigHashTypes = {
67     {static_cast<unsigned char>(SIGHASH_ALL), std::string("ALL")},
68     {static_cast<unsigned char>(SIGHASH_ALL|SIGHASH_ANYONECANPAY), std::string("ALL|ANYONECANPAY")},
69     {static_cast<unsigned char>(SIGHASH_NONE), std::string("NONE")},
70     {static_cast<unsigned char>(SIGHASH_NONE|SIGHASH_ANYONECANPAY), std::string("NONE|ANYONECANPAY")},
71     {static_cast<unsigned char>(SIGHASH_SINGLE), std::string("SINGLE")},
72     {static_cast<unsigned char>(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY), std::string("SINGLE|ANYONECANPAY")},
73 };
74 
SighashToStr(unsigned char sighash_type)75 std::string SighashToStr(unsigned char sighash_type)
76 {
77     const auto& it = mapSigHashTypes.find(sighash_type);
78     if (it == mapSigHashTypes.end()) return "";
79     return it->second;
80 }
81 
82 /**
83  * Create the assembly string representation of a CScript object.
84  * @param[in] script    CScript object to convert into the asm string representation.
85  * @param[in] fAttemptSighashDecode    Whether to attempt to decode sighash types on data within the script that matches the format
86  *                                     of a signature. Only pass true for scripts you believe could contain signatures. For example,
87  *                                     pass false, or omit the this argument (defaults to false), for scriptPubKeys.
88  */
ScriptToAsmStr(const CScript & script,const bool fAttemptSighashDecode)89 std::string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode)
90 {
91     std::string str;
92     opcodetype opcode;
93     opcodetype lastOpcode = OP_0;
94     std::vector<unsigned char> vch;
95     CScript::const_iterator pc = script.begin();
96     while (pc < script.end()) {
97         if (!str.empty()) {
98             str += " ";
99         }
100         if (!script.GetOp(pc, opcode, vch)) {
101             str += "[error]";
102             return str;
103         }
104         if (0 <= opcode && opcode <= OP_PUSHDATA4) {
105             if (vch.size() <= static_cast<std::vector<unsigned char>::size_type>(4)) {
106                 if ((lastOpcode == OP_NAME_NEW
107                       || lastOpcode == OP_NAME_UPDATE
108                       || lastOpcode == OP_NAME_FIRSTUPDATE)
109                     && !vch.empty()) {
110                       str += HexStr(vch);
111                 } else {
112                     str += strprintf("%d", CScriptNum(vch, false).getint());
113                 }
114             } else {
115                 // the IsUnspendable check makes sure not to try to decode OP_RETURN data that may match the format of a signature
116                 if (fAttemptSighashDecode && !script.IsUnspendable()) {
117                     std::string strSigHashDecode;
118                     // goal: only attempt to decode a defined sighash type from data that looks like a signature within a scriptSig.
119                     // this won't decode correctly formatted public keys in Pubkey or Multisig scripts due to
120                     // the restrictions on the pubkey formats (see IsCompressedOrUncompressedPubKey) being incongruous with the
121                     // checks in CheckSignatureEncoding.
122                     if (CheckSignatureEncoding(vch, SCRIPT_VERIFY_STRICTENC, nullptr)) {
123                         const unsigned char chSigHashType = vch.back();
124                         const auto it = mapSigHashTypes.find(chSigHashType);
125                         if (it != mapSigHashTypes.end()) {
126                             strSigHashDecode = "[" + it->second + "]";
127                             vch.pop_back(); // remove the sighash type byte. it will be replaced by the decode.
128                         }
129                     }
130                     str += HexStr(vch) + strSigHashDecode;
131                 } else {
132                     str += HexStr(vch);
133                 }
134             }
135         } else {
136             str += GetOpName(opcode);
137         }
138         lastOpcode = opcode;
139     }
140     return str;
141 }
142 
EncodeHexTx(const CTransaction & tx,const int serializeFlags)143 std::string EncodeHexTx(const CTransaction& tx, const int serializeFlags)
144 {
145     CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION | serializeFlags);
146     ssTx << tx;
147     return HexStr(ssTx);
148 }
149 
ScriptToUniv(const CScript & script,UniValue & out,bool include_address)150 void ScriptToUniv(const CScript& script, UniValue& out, bool include_address)
151 {
152     out.pushKV("asm", ScriptToAsmStr(script));
153     out.pushKV("hex", HexStr(script));
154 
155     std::vector<std::vector<unsigned char>> solns;
156     TxoutType type = Solver(script, solns);
157     out.pushKV("type", GetTxnOutputType(type));
158 
159     CTxDestination address;
160     if (include_address && ExtractDestination(script, address) && type != TxoutType::PUBKEY) {
161         out.pushKV("address", EncodeDestination(address));
162     }
163 }
164 
ScriptPubKeyToUniv(const CScript & scriptPubKey,UniValue & out,bool fIncludeHex)165 void ScriptPubKeyToUniv(const CScript& scriptPubKey,
166                         UniValue& out, bool fIncludeHex)
167 {
168     TxoutType type;
169     std::vector<CTxDestination> addresses;
170     int nRequired;
171 
172     const CNameScript nameOp(scriptPubKey);
173     if (nameOp.isNameOp ())
174         out.pushKV ("nameOp", NameOpToUniv (nameOp));
175 
176     out.pushKV("asm", ScriptToAsmStr(scriptPubKey));
177     if (fIncludeHex)
178         out.pushKV("hex", HexStr(scriptPubKey));
179 
180     if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired) || type == TxoutType::PUBKEY) {
181         out.pushKV("type", GetTxnOutputType(type));
182         return;
183     }
184 
185     out.pushKV("reqSigs", nRequired);
186     out.pushKV("type", GetTxnOutputType(type));
187 
188     UniValue a(UniValue::VARR);
189     for (const CTxDestination& addr : addresses) {
190         a.push_back(EncodeDestination(addr));
191     }
192     out.pushKV("addresses", a);
193 }
194 
TxToUniv(const CTransaction & tx,const uint256 & hashBlock,UniValue & entry,bool include_hex,int serialize_flags)195 void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex, int serialize_flags)
196 {
197     entry.pushKV("txid", tx.GetHash().GetHex());
198     entry.pushKV("hash", tx.GetWitnessHash().GetHex());
199     // Transaction version is actually unsigned in consensus checks, just signed in memory,
200     // so cast to unsigned before giving it to the user.
201     entry.pushKV("version", static_cast<int64_t>(static_cast<uint32_t>(tx.nVersion)));
202     entry.pushKV("size", (int)::GetSerializeSize(tx, PROTOCOL_VERSION));
203     entry.pushKV("vsize", (GetTransactionWeight(tx) + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR);
204     entry.pushKV("weight", GetTransactionWeight(tx));
205     entry.pushKV("locktime", (int64_t)tx.nLockTime);
206 
207     UniValue vin(UniValue::VARR);
208     for (unsigned int i = 0; i < tx.vin.size(); i++) {
209         const CTxIn& txin = tx.vin[i];
210         UniValue in(UniValue::VOBJ);
211         if (tx.IsCoinBase())
212             in.pushKV("coinbase", HexStr(txin.scriptSig));
213         else {
214             in.pushKV("txid", txin.prevout.hash.GetHex());
215             in.pushKV("vout", (int64_t)txin.prevout.n);
216             UniValue o(UniValue::VOBJ);
217             o.pushKV("asm", ScriptToAsmStr(txin.scriptSig, true));
218             o.pushKV("hex", HexStr(txin.scriptSig));
219             in.pushKV("scriptSig", o);
220         }
221         if (!tx.vin[i].scriptWitness.IsNull()) {
222             UniValue txinwitness(UniValue::VARR);
223             for (const auto& item : tx.vin[i].scriptWitness.stack) {
224                 txinwitness.push_back(HexStr(item));
225             }
226             in.pushKV("txinwitness", txinwitness);
227         }
228         in.pushKV("sequence", (int64_t)txin.nSequence);
229         vin.push_back(in);
230     }
231     entry.pushKV("vin", vin);
232 
233     UniValue vout(UniValue::VARR);
234     for (unsigned int i = 0; i < tx.vout.size(); i++) {
235         const CTxOut& txout = tx.vout[i];
236 
237         UniValue out(UniValue::VOBJ);
238 
239         out.pushKV("value", ValueFromAmount(txout.nValue));
240         out.pushKV("n", (int64_t)i);
241 
242         UniValue o(UniValue::VOBJ);
243         ScriptPubKeyToUniv(txout.scriptPubKey, o, true);
244         out.pushKV("scriptPubKey", o);
245         vout.push_back(out);
246     }
247     entry.pushKV("vout", vout);
248 
249     if (!hashBlock.IsNull())
250         entry.pushKV("blockhash", hashBlock.GetHex());
251 
252     if (include_hex) {
253         entry.pushKV("hex", EncodeHexTx(tx, serialize_flags)); // The hex-encoded transaction. Used the name "hex" to be consistent with the verbose output of "getrawtransaction".
254     }
255 }
256 
NameOpToUniv(const CNameScript & nameOp)257 UniValue NameOpToUniv (const CNameScript& nameOp)
258 {
259   assert (nameOp.isNameOp ());
260 
261   UniValue result(UniValue::VOBJ);
262   switch (nameOp.getNameOp ())
263     {
264       case OP_NAME_NEW:
265         result.pushKV ("op", "name_new");
266         result.pushKV ("hash", HexStr (nameOp.getOpHash ()));
267         break;
268 
269       case OP_NAME_FIRSTUPDATE:
270         result.pushKV ("op", "name_firstupdate");
271         AddEncodedNameToUniv (result, "name", nameOp.getOpName (),
272                               ConfiguredNameEncoding ());
273         AddEncodedNameToUniv (result, "value", nameOp.getOpValue (),
274                               ConfiguredValueEncoding ());
275         result.pushKV ("rand", HexStr (nameOp.getOpRand ()));
276         break;
277 
278       case OP_NAME_UPDATE:
279         result.pushKV ("op", "name_update");
280         AddEncodedNameToUniv (result, "name", nameOp.getOpName (),
281                               ConfiguredNameEncoding ());
282         AddEncodedNameToUniv (result, "value", nameOp.getOpValue (),
283                               ConfiguredValueEncoding ());
284         break;
285 
286       default:
287         assert (false);
288     }
289 
290   return result;
291 }
292