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 65 : UniValue ValueFromAmount(const CAmount amount)
36 : {
37 : static_assert(COIN > 1);
38 65 : int64_t quotient = amount / COIN;
39 65 : int64_t remainder = amount % COIN;
40 65 : if (amount < 0) {
41 6 : quotient = -quotient;
42 6 : remainder = -remainder;
43 6 : }
44 65 : return UniValue(UniValue::VNUM,
45 65 : 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 218 : const std::map<unsigned char, std::string> mapSigHashTypes = {
85 218 : {static_cast<unsigned char>(SIGHASH_ALL), std::string("ALL")},
86 218 : {static_cast<unsigned char>(SIGHASH_ALL|SIGHASH_ANYONECANPAY), std::string("ALL|ANYONECANPAY")},
87 218 : {static_cast<unsigned char>(SIGHASH_NONE), std::string("NONE")},
88 218 : {static_cast<unsigned char>(SIGHASH_NONE|SIGHASH_ANYONECANPAY), std::string("NONE|ANYONECANPAY")},
89 218 : {static_cast<unsigned char>(SIGHASH_SINGLE), std::string("SINGLE")},
90 218 : {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 114 : std::string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode)
108 : {
109 114 : std::string str;
110 : opcodetype opcode;
111 114 : std::vector<unsigned char> vch;
112 114 : CScript::const_iterator pc = script.begin();
113 362 : while (pc < script.end()) {
114 248 : if (!str.empty()) {
115 144 : str += " ";
116 144 : }
117 248 : if (!script.GetOp(pc, opcode, vch)) {
118 0 : str += "[error]";
119 0 : return str;
120 : }
121 248 : if (0 <= opcode && opcode <= OP_PUSHDATA4) {
122 181 : if (vch.size() <= static_cast<std::vector<unsigned char>::size_type>(4)) {
123 0 : str += strprintf("%d", CScriptNum(vch, false).getint());
124 0 : } else {
125 : // the IsUnspendable check makes sure not to try to decode OP_RETURN data that may match the format of a signature
126 181 : if (fAttemptSighashDecode && !script.IsUnspendable()) {
127 144 : 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 144 : if (CheckSignatureEncoding(vch, SCRIPT_VERIFY_STRICTENC, nullptr)) {
133 70 : const unsigned char chSigHashType = vch.back();
134 70 : const auto it = mapSigHashTypes.find(chSigHashType);
135 70 : if (it != mapSigHashTypes.end()) {
136 70 : strSigHashDecode = "[" + it->second + "]";
137 70 : vch.pop_back(); // remove the sighash type byte. it will be replaced by the decode.
138 70 : }
139 70 : }
140 144 : str += HexStr(vch) + strSigHashDecode;
141 144 : } else {
142 37 : str += HexStr(vch);
143 : }
144 : }
145 181 : } else {
146 67 : str += GetOpName(opcode);
147 : }
148 : }
149 114 : return str;
150 114 : }
151 :
152 47 : std::string EncodeHexTx(const CTransaction& tx)
153 : {
154 47 : CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
155 47 : ssTx << tx;
156 47 : return HexStr(ssTx);
157 47 : }
158 :
159 22 : void ScriptToUniv(const CScript& script, UniValue& out, bool include_hex, bool include_address)
160 : {
161 22 : CTxDestination address;
162 :
163 22 : out.pushKV("asm", ScriptToAsmStr(script));
164 22 : if (include_address) {
165 22 : out.pushKV("desc", InferDescriptor(script, DUMMY_SIGNING_PROVIDER)->ToString());
166 22 : }
167 22 : if (include_hex) {
168 22 : out.pushKV("hex", HexStr(script));
169 22 : }
170 :
171 22 : std::vector<std::vector<unsigned char>> solns;
172 22 : const TxoutType type{Solver(script, solns)};
173 :
174 22 : if (include_address && ExtractDestination(script, address) && type != TxoutType::PUBKEY) {
175 15 : out.pushKV("address", EncodeDestination(address));
176 15 : }
177 22 : out.pushKV("type", GetTxnOutputType(type));
178 22 : }
179 :
180 20 : 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 20 : CHECK_NONFATAL(verbosity >= TxVerbosity::SHOW_DETAILS);
183 :
184 20 : uint256 txid = tx.GetHash();
185 20 : 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 20 : entry.pushKV("version", static_cast<int64_t>(static_cast<uint16_t>(tx.nVersion)));
189 20 : entry.pushKV("type", tx.nType);
190 20 : entry.pushKV("size", (int)::GetSerializeSize(tx, PROTOCOL_VERSION));
191 20 : entry.pushKV("locktime", (int64_t)tx.nLockTime);
192 :
193 20 : 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 20 : const bool have_undo = txundo != nullptr;
198 20 : CAmount amt_total_in = 0;
199 20 : CAmount amt_total_out = 0;
200 :
201 92 : for (unsigned int i = 0; i < tx.vin.size(); i++) {
202 72 : const CTxIn& txin = tx.vin[i];
203 72 : UniValue in(UniValue::VOBJ);
204 72 : if (tx.IsCoinBase()) {
205 0 : in.pushKV("coinbase", HexStr(txin.scriptSig));
206 0 : } else {
207 72 : in.pushKV("txid", txin.prevout.hash.GetHex());
208 72 : in.pushKV("vout", (int64_t)txin.prevout.n);
209 72 : UniValue o(UniValue::VOBJ);
210 72 : o.pushKV("asm", ScriptToAsmStr(txin.scriptSig, true));
211 72 : o.pushKV("hex", HexStr(txin.scriptSig));
212 72 : in.pushKV("scriptSig", o);
213 :
214 : // Add address and value info if spentindex enabled
215 72 : if (ptxSpentInfo != nullptr) {
216 0 : CSpentIndexKey spentKey(txin.prevout.hash, txin.prevout.n);
217 0 : auto it = ptxSpentInfo->mSpentInfo.find(spentKey);
218 0 : if (it != ptxSpentInfo->mSpentInfo.end()) {
219 0 : auto spentInfo = it->second;
220 0 : in.pushKV("value", ValueFromAmount(spentInfo.m_amount));
221 0 : in.pushKV("valueSat", spentInfo.m_amount);
222 0 : if (spentInfo.m_address_type == AddressType::P2PK_OR_P2PKH) {
223 0 : in.pushKV("address", EncodeDestination(PKHash(spentInfo.m_address_bytes)));
224 0 : } else if (spentInfo.m_address_type == AddressType::P2SH) {
225 0 : in.pushKV("address", EncodeDestination(ScriptHash(spentInfo.m_address_bytes)));
226 0 : }
227 0 : }
228 0 : }
229 72 : }
230 72 : if (have_undo) {
231 0 : const Coin& prev_coin = txundo->vprevout[i];
232 0 : const CTxOut& prev_txout = prev_coin.out;
233 :
234 0 : amt_total_in += prev_txout.nValue;
235 :
236 0 : if (verbosity == TxVerbosity::SHOW_DETAILS_AND_PREVOUT) {
237 0 : UniValue o_script_pub_key(UniValue::VOBJ);
238 0 : ScriptToUniv(prev_txout.scriptPubKey, /*out=*/o_script_pub_key, /*include_hex=*/true, /*include_address=*/true);
239 :
240 0 : UniValue p(UniValue::VOBJ);
241 0 : p.pushKV("generated", bool(prev_coin.fCoinBase));
242 0 : p.pushKV("height", uint64_t(prev_coin.nHeight));
243 0 : p.pushKV("value", ValueFromAmount(prev_txout.nValue));
244 0 : p.pushKV("scriptPubKey", o_script_pub_key);
245 0 : in.pushKV("prevout", p);
246 0 : }
247 0 : }
248 72 : in.pushKV("sequence", (int64_t)txin.nSequence);
249 72 : vin.push_back(in);
250 72 : }
251 20 : entry.pushKV("vin", vin);
252 :
253 20 : UniValue vout(UniValue::VARR);
254 42 : for (unsigned int i = 0; i < tx.vout.size(); i++) {
255 22 : const CTxOut& txout = tx.vout[i];
256 :
257 22 : UniValue out(UniValue::VOBJ);
258 :
259 22 : out.pushKV("value", ValueFromAmount(txout.nValue));
260 22 : out.pushKV("valueSat", txout.nValue);
261 22 : out.pushKV("n", (int64_t)i);
262 :
263 22 : UniValue o(UniValue::VOBJ);
264 22 : ScriptToUniv(txout.scriptPubKey, /*out=*/o, /*include_hex=*/true, /*include_address=*/true);
265 22 : out.pushKV("scriptPubKey", o);
266 :
267 : // Add spent information if spentindex is enabled
268 22 : if (ptxSpentInfo != nullptr) {
269 0 : CSpentIndexKey spentKey(txid, i);
270 0 : auto it = ptxSpentInfo->mSpentInfo.find(spentKey);
271 0 : if (it != ptxSpentInfo->mSpentInfo.end()) {
272 0 : auto spentInfo = it->second;
273 0 : out.pushKV("spentTxId", spentInfo.m_tx_hash.GetHex());
274 0 : out.pushKV("spentIndex", spentInfo.m_tx_index);
275 0 : out.pushKV("spentHeight", spentInfo.m_block_height);
276 0 : }
277 0 : }
278 22 : vout.push_back(out);
279 :
280 22 : if (have_undo) {
281 0 : amt_total_out += txout.nValue;
282 0 : }
283 22 : }
284 20 : entry.pushKV("vout", vout);
285 :
286 20 : if (!tx.vExtraPayload.empty()) {
287 0 : entry.pushKV("extraPayloadSize", tx.vExtraPayload.size());
288 0 : entry.pushKV("extraPayload", HexStr(tx.vExtraPayload));
289 0 : }
290 :
291 20 : if (tx.nType == TRANSACTION_PROVIDER_REGISTER) {
292 0 : if (const auto opt_proTx = GetTxPayload<CProRegTx>(tx)) {
293 0 : entry.pushKV("proRegTx", opt_proTx->ToJson());
294 0 : }
295 20 : } else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_SERVICE) {
296 0 : if (const auto opt_proTx = GetTxPayload<CProUpServTx>(tx)) {
297 0 : entry.pushKV("proUpServTx", opt_proTx->ToJson());
298 0 : }
299 20 : } 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 20 : } else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_REVOKE) {
304 0 : if (const auto opt_proTx = GetTxPayload<CProUpRevTx>(tx)) {
305 0 : entry.pushKV("proUpRevTx", opt_proTx->ToJson());
306 0 : }
307 20 : } else if (tx.nType == TRANSACTION_COINBASE) {
308 0 : if (const auto opt_cbTx = GetTxPayload<CCbTx>(tx)) {
309 0 : entry.pushKV("cbTx", opt_cbTx->ToJson());
310 0 : }
311 20 : } else if (tx.nType == TRANSACTION_QUORUM_COMMITMENT) {
312 0 : if (const auto opt_qcTx = GetTxPayload<llmq::CFinalCommitmentTxPayload>(tx)) {
313 0 : entry.pushKV("qcTx", opt_qcTx->ToJson());
314 0 : }
315 20 : } 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 20 : } else if (tx.nType == TRANSACTION_ASSET_LOCK) {
320 0 : if (const auto opt_assetLockTx = GetTxPayload<CAssetLockPayload>(tx)) {
321 0 : entry.pushKV("assetLockTx", opt_assetLockTx->ToJson());
322 0 : }
323 20 : } else if (tx.nType == TRANSACTION_ASSET_UNLOCK) {
324 0 : if (const auto opt_assetUnlockTx = GetTxPayload<CAssetUnlockPayload>(tx)) {
325 0 : entry.pushKV("assetUnlockTx", opt_assetUnlockTx->ToJson());
326 0 : }
327 0 : }
328 :
329 20 : if (have_undo) {
330 0 : CAmount fee = amt_total_in - amt_total_out;
331 0 : if (tx.IsPlatformTransfer()) {
332 0 : auto payload = GetTxPayload<CAssetUnlockPayload>(tx);
333 0 : CHECK_NONFATAL(payload);
334 0 : fee = payload->getFee();
335 0 : }
336 0 : CHECK_NONFATAL(MoneyRange(fee));
337 0 : entry.pushKV("fee", ValueFromAmount(fee));
338 0 : }
339 :
340 20 : if (!block_hash.IsNull()) {
341 0 : entry.pushKV("blockhash", block_hash.GetHex());
342 0 : }
343 :
344 20 : if (include_hex) {
345 19 : entry.pushKV("hex", EncodeHexTx(tx)); // The hex-encoded transaction. Used the name "hex" to be consistent with the verbose output of "getrawtransaction".
346 19 : }
347 20 : }
|