Line data Source code
1 : // Copyright (c) 2009-2021 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/amount.h>
8 : #include <consensus/validation.h>
9 : #include <key_io.h>
10 : #include <primitives/transaction.h>
11 : #include <script/descriptor.h>
12 : #include <script/script.h>
13 : #include <script/standard.h>
14 : #include <serialize.h>
15 : #include <streams.h>
16 : #include <undo.h>
17 : #include <univalue.h>
18 : #include <util/check.h>
19 : #include <util/strencodings.h>
20 : #include <util/system.h>
21 :
22 : #include <index/spentindex.h>
23 :
24 : #include <evo/assetlocktx.h>
25 : #include <evo/cbtx.h>
26 : #include <evo/mnhftx.h>
27 : #include <evo/providertx.h>
28 : #include <evo/specialtx.h>
29 : #include <llmq/commitment.h>
30 :
31 : #include <map>
32 : #include <string>
33 : #include <vector>
34 :
35 323580 : UniValue ValueFromAmount(const CAmount amount)
36 : {
37 : static_assert(COIN > 1);
38 323580 : int64_t quotient = amount / COIN;
39 323580 : int64_t remainder = amount % COIN;
40 323580 : if (amount < 0) {
41 2998 : quotient = -quotient;
42 2998 : remainder = -remainder;
43 2998 : }
44 323580 : return UniValue(UniValue::VNUM,
45 323580 : strprintf("%s%d.%08d", amount < 0 ? "-" : "", quotient, remainder));
46 0 : }
47 :
48 212 : std::string FormatScript(const CScript& script)
49 : {
50 212 : std::string ret;
51 212 : CScript::const_iterator it = script.begin();
52 : opcodetype op;
53 664 : while (it != script.end()) {
54 876 : CScript::const_iterator it2 = it;
55 876 : std::vector<unsigned char> vch;
56 876 : if (script.GetOp(it, op, vch)) {
57 558 : if (op == OP_0) {
58 58 : ret += "0 ";
59 58 : continue;
60 500 : } else if ((op >= OP_1 && op <= OP_16) || op == OP_1NEGATE) {
61 394 : ret += strprintf("%i ", op - OP_1NEGATE - 1);
62 76 : continue;
63 424 : } else if (op >= OP_NOP && op <= OP_NOP10) {
64 135 : std::string str(GetOpName(op));
65 135 : if (str.substr(0, 3) == std::string("OP_")) {
66 135 : ret += str.substr(3, std::string::npos) + " ";
67 135 : continue;
68 : }
69 135 : }
70 289 : if (vch.size() > 0) {
71 530 : ret += strprintf("0x%x 0x%x ", HexStr(std::vector<uint8_t>(it2, it - vch.size())),
72 265 : HexStr(std::vector<uint8_t>(it - vch.size(), it)));
73 265 : } else {
74 24 : ret += strprintf("0x%x ", HexStr(std::vector<uint8_t>(it2, it)));
75 : }
76 289 : continue;
77 : }
78 0 : ret += strprintf("0x%x ", HexStr(std::vector<uint8_t>(it2, script.end())));
79 0 : break;
80 558 : }
81 212 : return ret.substr(0, ret.empty() ? ret.npos : ret.size() - 1);
82 954 : }
83 :
84 3516 : const std::map<unsigned char, std::string> mapSigHashTypes = {
85 3516 : {static_cast<unsigned char>(SIGHASH_ALL), std::string("ALL")},
86 3516 : {static_cast<unsigned char>(SIGHASH_ALL|SIGHASH_ANYONECANPAY), std::string("ALL|ANYONECANPAY")},
87 3516 : {static_cast<unsigned char>(SIGHASH_NONE), std::string("NONE")},
88 3516 : {static_cast<unsigned char>(SIGHASH_NONE|SIGHASH_ANYONECANPAY), std::string("NONE|ANYONECANPAY")},
89 3516 : {static_cast<unsigned char>(SIGHASH_SINGLE), std::string("SINGLE")},
90 3516 : {static_cast<unsigned char>(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY), std::string("SINGLE|ANYONECANPAY")},
91 : };
92 :
93 0 : std::string SighashToStr(unsigned char sighash_type)
94 : {
95 0 : const auto& it = mapSigHashTypes.find(sighash_type);
96 0 : if (it == mapSigHashTypes.end()) return "";
97 0 : return it->second;
98 0 : }
99 :
100 : /**
101 : * Create the assembly string representation of a CScript object.
102 : * @param[in] script CScript object to convert into the asm string representation.
103 : * @param[in] fAttemptSighashDecode Whether to attempt to decode sighash types on data within the script that matches the format
104 : * of a signature. Only pass true for scripts you believe could contain signatures. For example,
105 : * pass false, or omit the this argument (defaults to false), for scriptPubKeys.
106 : */
107 51762 : std::string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode)
108 : {
109 51762 : std::string str;
110 : opcodetype opcode;
111 51762 : std::vector<unsigned char> vch;
112 51762 : CScript::const_iterator pc = script.begin();
113 213763 : while (pc < script.end()) {
114 162001 : if (!str.empty()) {
115 110961 : str += " ";
116 110961 : }
117 162001 : if (!script.GetOp(pc, opcode, vch)) {
118 0 : str += "[error]";
119 0 : return str;
120 : }
121 162001 : if (0 <= opcode && opcode <= OP_PUSHDATA4) {
122 58336 : if (vch.size() <= static_cast<std::vector<unsigned char>::size_type>(4)) {
123 11818 : str += strprintf("%d", CScriptNum(vch, false).getint());
124 11818 : } else {
125 : // the IsUnspendable check makes sure not to try to decode OP_RETURN data that may match the format of a signature
126 46518 : if (fAttemptSighashDecode && !script.IsUnspendable()) {
127 14651 : std::string strSigHashDecode;
128 : // goal: only attempt to decode a defined sighash type from data that looks like a signature within a scriptSig.
129 : // this won't decode correctly formatted public keys in Pubkey or Multisig scripts due to
130 : // the restrictions on the pubkey formats (see IsCompressedOrUncompressedPubKey) being incongruous with the
131 : // checks in CheckSignatureEncoding.
132 14651 : if (CheckSignatureEncoding(vch, SCRIPT_VERIFY_STRICTENC, nullptr)) {
133 7391 : const unsigned char chSigHashType = vch.back();
134 7391 : const auto it = mapSigHashTypes.find(chSigHashType);
135 7391 : if (it != mapSigHashTypes.end()) {
136 7391 : strSigHashDecode = "[" + it->second + "]";
137 7391 : vch.pop_back(); // remove the sighash type byte. it will be replaced by the decode.
138 7391 : }
139 7391 : }
140 14651 : str += HexStr(vch) + strSigHashDecode;
141 14651 : } else {
142 31867 : str += HexStr(vch);
143 : }
144 : }
145 58336 : } else {
146 103665 : str += GetOpName(opcode);
147 : }
148 : }
149 51762 : return str;
150 51762 : }
151 :
152 12818 : std::string EncodeHexTx(const CTransaction& tx)
153 : {
154 12818 : CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
155 12818 : ssTx << tx;
156 12818 : return HexStr(ssTx);
157 12818 : }
158 :
159 31914 : void ScriptToUniv(const CScript& script, UniValue& out, bool include_hex, bool include_address)
160 : {
161 31914 : CTxDestination address;
162 :
163 31914 : out.pushKV("asm", ScriptToAsmStr(script));
164 31914 : if (include_address) {
165 31860 : out.pushKV("desc", InferDescriptor(script, DUMMY_SIGNING_PROVIDER)->ToString());
166 31860 : }
167 31914 : if (include_hex) {
168 31890 : out.pushKV("hex", HexStr(script));
169 31890 : }
170 :
171 31914 : std::vector<std::vector<unsigned char>> solns;
172 31914 : const TxoutType type{Solver(script, solns)};
173 :
174 31914 : if (include_address && ExtractDestination(script, address) && type != TxoutType::PUBKEY) {
175 31187 : out.pushKV("address", EncodeDestination(address));
176 31187 : }
177 31914 : out.pushKV("type", GetTxnOutputType(type));
178 31914 : }
179 :
180 8934 : void TxToUniv(const CTransaction& tx, const uint256& block_hash, UniValue& entry, bool include_hex, int serialize_flags, const CTxUndo* txundo, TxVerbosity verbosity, const CSpentIndexTxInfo* ptxSpentInfo)
181 : {
182 8934 : CHECK_NONFATAL(verbosity >= TxVerbosity::SHOW_DETAILS);
183 :
184 8934 : uint256 txid = tx.GetHash();
185 8938 : entry.pushKV("txid", txid.GetHex());
186 : // Transaction version is actually unsigned in consensus checks, just signed in memory,
187 : // so cast to unsigned before giving it to the user.
188 8934 : entry.pushKV("version", static_cast<int64_t>(static_cast<uint16_t>(tx.nVersion)));
189 8934 : entry.pushKV("type", tx.nType);
190 8934 : entry.pushKV("size", (int)::GetSerializeSize(tx, PROTOCOL_VERSION));
191 8934 : entry.pushKV("locktime", (int64_t)tx.nLockTime);
192 :
193 8934 : UniValue vin(UniValue::VARR);
194 :
195 : // If available, use Undo data to calculate the fee. Note that txundo == nullptr
196 : // for coinbase transactions and for transactions where undo data is unavailable.
197 8934 : const bool have_undo = txundo != nullptr;
198 8934 : CAmount amt_total_in = 0;
199 8934 : CAmount amt_total_out = 0;
200 :
201 29014 : for (unsigned int i = 0; i < tx.vin.size(); i++) {
202 20080 : const CTxIn& txin = tx.vin[i];
203 20080 : UniValue in(UniValue::VOBJ);
204 20080 : if (tx.IsCoinBase()) {
205 354 : in.pushKV("coinbase", HexStr(txin.scriptSig));
206 354 : } else {
207 19726 : in.pushKV("txid", txin.prevout.hash.GetHex());
208 19726 : in.pushKV("vout", (int64_t)txin.prevout.n);
209 19726 : UniValue o(UniValue::VOBJ);
210 19726 : o.pushKV("asm", ScriptToAsmStr(txin.scriptSig, true));
211 19726 : o.pushKV("hex", HexStr(txin.scriptSig));
212 19726 : in.pushKV("scriptSig", o);
213 :
214 : // Add address and value info if spentindex enabled
215 19726 : if (ptxSpentInfo != nullptr) {
216 6 : CSpentIndexKey spentKey(txin.prevout.hash, txin.prevout.n);
217 6 : auto it = ptxSpentInfo->mSpentInfo.find(spentKey);
218 6 : if (it != ptxSpentInfo->mSpentInfo.end()) {
219 6 : auto spentInfo = it->second;
220 6 : in.pushKV("value", ValueFromAmount(spentInfo.m_amount));
221 6 : in.pushKV("valueSat", spentInfo.m_amount);
222 6 : if (spentInfo.m_address_type == AddressType::P2PK_OR_P2PKH) {
223 6 : in.pushKV("address", EncodeDestination(PKHash(spentInfo.m_address_bytes)));
224 6 : } else if (spentInfo.m_address_type == AddressType::P2SH) {
225 0 : in.pushKV("address", EncodeDestination(ScriptHash(spentInfo.m_address_bytes)));
226 0 : }
227 6 : }
228 6 : }
229 19726 : }
230 20080 : if (have_undo) {
231 40 : const Coin& prev_coin = txundo->vprevout[i];
232 40 : const CTxOut& prev_txout = prev_coin.out;
233 :
234 40 : amt_total_in += prev_txout.nValue;
235 :
236 40 : if (verbosity == TxVerbosity::SHOW_DETAILS_AND_PREVOUT) {
237 14 : UniValue o_script_pub_key(UniValue::VOBJ);
238 14 : ScriptToUniv(prev_txout.scriptPubKey, /*out=*/o_script_pub_key, /*include_hex=*/true, /*include_address=*/true);
239 :
240 14 : UniValue p(UniValue::VOBJ);
241 14 : p.pushKV("generated", bool(prev_coin.fCoinBase));
242 14 : p.pushKV("height", uint64_t(prev_coin.nHeight));
243 14 : p.pushKV("value", ValueFromAmount(prev_txout.nValue));
244 14 : p.pushKV("scriptPubKey", o_script_pub_key);
245 14 : in.pushKV("prevout", p);
246 14 : }
247 40 : }
248 20080 : in.pushKV("sequence", (int64_t)txin.nSequence);
249 20080 : vin.push_back(in);
250 20080 : }
251 8934 : entry.pushKV("vin", vin);
252 :
253 8934 : UniValue vout(UniValue::VARR);
254 25821 : for (unsigned int i = 0; i < tx.vout.size(); i++) {
255 16887 : const CTxOut& txout = tx.vout[i];
256 :
257 16887 : UniValue out(UniValue::VOBJ);
258 :
259 16887 : out.pushKV("value", ValueFromAmount(txout.nValue));
260 16887 : out.pushKV("valueSat", txout.nValue);
261 16887 : out.pushKV("n", (int64_t)i);
262 :
263 16887 : UniValue o(UniValue::VOBJ);
264 16887 : ScriptToUniv(txout.scriptPubKey, /*out=*/o, /*include_hex=*/true, /*include_address=*/true);
265 16887 : out.pushKV("scriptPubKey", o);
266 :
267 : // Add spent information if spentindex is enabled
268 16887 : if (ptxSpentInfo != nullptr) {
269 8 : CSpentIndexKey spentKey(txid, i);
270 8 : auto it = ptxSpentInfo->mSpentInfo.find(spentKey);
271 8 : if (it != ptxSpentInfo->mSpentInfo.end()) {
272 2 : auto spentInfo = it->second;
273 2 : out.pushKV("spentTxId", spentInfo.m_tx_hash.GetHex());
274 2 : out.pushKV("spentIndex", spentInfo.m_tx_index);
275 2 : out.pushKV("spentHeight", spentInfo.m_block_height);
276 2 : }
277 8 : }
278 16887 : vout.push_back(out);
279 :
280 16887 : if (have_undo) {
281 47 : amt_total_out += txout.nValue;
282 47 : }
283 16887 : }
284 8934 : entry.pushKV("vout", vout);
285 :
286 8934 : if (!tx.vExtraPayload.empty()) {
287 333 : entry.pushKV("extraPayloadSize", tx.vExtraPayload.size());
288 333 : entry.pushKV("extraPayload", HexStr(tx.vExtraPayload));
289 333 : }
290 :
291 8934 : if (tx.nType == TRANSACTION_PROVIDER_REGISTER) {
292 226 : if (const auto opt_proTx = GetTxPayload<CProRegTx>(tx)) {
293 115 : entry.pushKV("proRegTx", opt_proTx->ToJson());
294 111 : }
295 8932 : } else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_SERVICE) {
296 84 : if (const auto opt_proTx = GetTxPayload<CProUpServTx>(tx)) {
297 44 : entry.pushKV("proUpServTx", opt_proTx->ToJson());
298 40 : }
299 8819 : } else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_REGISTRAR) {
300 0 : if (const auto opt_proTx = GetTxPayload<CProUpRegTx>(tx)) {
301 0 : entry.pushKV("proUpRegTx", opt_proTx->ToJson());
302 0 : }
303 8779 : } else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_REVOKE) {
304 12 : if (const auto opt_proTx = GetTxPayload<CProUpRevTx>(tx)) {
305 6 : entry.pushKV("proUpRevTx", opt_proTx->ToJson());
306 6 : }
307 8779 : } else if (tx.nType == TRANSACTION_COINBASE) {
308 168 : if (const auto opt_cbTx = GetTxPayload<CCbTx>(tx)) {
309 84 : entry.pushKV("cbTx", opt_cbTx->ToJson());
310 84 : }
311 8773 : } else if (tx.nType == TRANSACTION_QUORUM_COMMITMENT) {
312 128 : if (const auto opt_qcTx = GetTxPayload<llmq::CFinalCommitmentTxPayload>(tx)) {
313 64 : entry.pushKV("qcTx", opt_qcTx->ToJson());
314 64 : }
315 8689 : } else if (tx.nType == TRANSACTION_MNHF_SIGNAL) {
316 0 : if (const auto opt_mnhfTx = GetTxPayload<MNHFTxPayload>(tx)) {
317 0 : entry.pushKV("mnhfTx", opt_mnhfTx->ToJson());
318 0 : }
319 8625 : } else if (tx.nType == TRANSACTION_ASSET_LOCK) {
320 18 : if (const auto opt_assetLockTx = GetTxPayload<CAssetLockPayload>(tx)) {
321 9 : entry.pushKV("assetLockTx", opt_assetLockTx->ToJson());
322 9 : }
323 8625 : } else if (tx.nType == TRANSACTION_ASSET_UNLOCK) {
324 30 : if (const auto opt_assetUnlockTx = GetTxPayload<CAssetUnlockPayload>(tx)) {
325 15 : entry.pushKV("assetUnlockTx", opt_assetUnlockTx->ToJson());
326 15 : }
327 15 : }
328 :
329 8930 : if (have_undo) {
330 104 : CAmount fee = amt_total_in - amt_total_out;
331 104 : if (tx.IsPlatformTransfer()) {
332 3 : auto payload = GetTxPayload<CAssetUnlockPayload>(tx);
333 3 : CHECK_NONFATAL(payload);
334 3 : fee = payload->getFee();
335 3 : }
336 104 : CHECK_NONFATAL(MoneyRange(fee));
337 104 : entry.pushKV("fee", ValueFromAmount(fee));
338 104 : }
339 :
340 8930 : if (!block_hash.IsNull()) {
341 0 : entry.pushKV("blockhash", block_hash.GetHex());
342 0 : }
343 :
344 8930 : if (include_hex) {
345 6874 : entry.pushKV("hex", EncodeHexTx(tx)); // The hex-encoded transaction. Used the name "hex" to be consistent with the verbose output of "getrawtransaction".
346 6874 : }
347 8938 : }
|