/root/bitcoin/src/core_write.cpp
| Line | Count | Source | 
| 1 |  | // Copyright (c) 2009-2022 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 <common/system.h> | 
| 8 |  | #include <consensus/amount.h> | 
| 9 |  | #include <consensus/consensus.h> | 
| 10 |  | #include <consensus/validation.h> | 
| 11 |  | #include <key_io.h> | 
| 12 |  | #include <script/descriptor.h> | 
| 13 |  | #include <script/script.h> | 
| 14 |  | #include <script/solver.h> | 
| 15 |  | #include <serialize.h> | 
| 16 |  | #include <streams.h> | 
| 17 |  | #include <undo.h> | 
| 18 |  | #include <univalue.h> | 
| 19 |  | #include <util/check.h> | 
| 20 |  | #include <util/strencodings.h> | 
| 21 |  |  | 
| 22 |  | #include <map> | 
| 23 |  | #include <string> | 
| 24 |  | #include <vector> | 
| 25 |  |  | 
| 26 |  | UniValue ValueFromAmount(const CAmount amount) | 
| 27 | 0 | { | 
| 28 | 0 |     static_assert(COIN > 1); | 
| 29 | 0 |     int64_t quotient = amount / COIN; | 
| 30 | 0 |     int64_t remainder = amount % COIN; | 
| 31 | 0 |     if (amount < 0) { | 
| 32 | 0 |         quotient = -quotient; | 
| 33 | 0 |         remainder = -remainder; | 
| 34 | 0 |     } | 
| 35 | 0 |     return UniValue(UniValue::VNUM, | 
| 36 | 0 |             strprintf("%s%d.%08d", amount < 0 ? "-" : "", quotient, remainder)); | 
| 37 | 0 | } | 
| 38 |  |  | 
| 39 |  | std::string FormatScript(const CScript& script) | 
| 40 | 0 | { | 
| 41 | 0 |     std::string ret; | 
| 42 | 0 |     CScript::const_iterator it = script.begin(); | 
| 43 | 0 |     opcodetype op; | 
| 44 | 0 |     while (it != script.end()) { | 
| 45 | 0 |         CScript::const_iterator it2 = it; | 
| 46 | 0 |         std::vector<unsigned char> vch; | 
| 47 | 0 |         if (script.GetOp(it, op, vch)) { | 
| 48 | 0 |             if (op == OP_0) { | 
| 49 | 0 |                 ret += "0 "; | 
| 50 | 0 |                 continue; | 
| 51 | 0 |             } else if ((op >= OP_1 && op <= OP_16) || op == OP_1NEGATE) { | 
| 52 | 0 |                 ret += strprintf("%i ", op - OP_1NEGATE - 1); | 
| 53 | 0 |                 continue; | 
| 54 | 0 |             } else if (op >= OP_NOP && op <= OP_NOP10) { | 
| 55 | 0 |                 std::string str(GetOpName(op)); | 
| 56 | 0 |                 if (str.substr(0, 3) == std::string("OP_")) { | 
| 57 | 0 |                     ret += str.substr(3, std::string::npos) + " "; | 
| 58 | 0 |                     continue; | 
| 59 | 0 |                 } | 
| 60 | 0 |             } | 
| 61 | 0 |             if (vch.size() > 0) { | 
| 62 | 0 |                 ret += strprintf("0x%x 0x%x ", HexStr(std::vector<uint8_t>(it2, it - vch.size())), | 
| 63 | 0 |                                                HexStr(std::vector<uint8_t>(it - vch.size(), it))); | 
| 64 | 0 |             } else { | 
| 65 | 0 |                 ret += strprintf("0x%x ", HexStr(std::vector<uint8_t>(it2, it))); | 
| 66 | 0 |             } | 
| 67 | 0 |             continue; | 
| 68 | 0 |         } | 
| 69 | 0 |         ret += strprintf("0x%x ", HexStr(std::vector<uint8_t>(it2, script.end()))); | 
| 70 | 0 |         break; | 
| 71 | 0 |     } | 
| 72 | 0 |     return ret.substr(0, ret.empty() ? ret.npos : ret.size() - 1); | 
| 73 | 0 | } | 
| 74 |  |  | 
| 75 |  | const std::map<unsigned char, std::string> mapSigHashTypes = { | 
| 76 |  |     {static_cast<unsigned char>(SIGHASH_ALL), std::string("ALL")}, | 
| 77 |  |     {static_cast<unsigned char>(SIGHASH_ALL|SIGHASH_ANYONECANPAY), std::string("ALL|ANYONECANPAY")}, | 
| 78 |  |     {static_cast<unsigned char>(SIGHASH_NONE), std::string("NONE")}, | 
| 79 |  |     {static_cast<unsigned char>(SIGHASH_NONE|SIGHASH_ANYONECANPAY), std::string("NONE|ANYONECANPAY")}, | 
| 80 |  |     {static_cast<unsigned char>(SIGHASH_SINGLE), std::string("SINGLE")}, | 
| 81 |  |     {static_cast<unsigned char>(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY), std::string("SINGLE|ANYONECANPAY")}, | 
| 82 |  | }; | 
| 83 |  |  | 
| 84 |  | std::string SighashToStr(unsigned char sighash_type) | 
| 85 | 0 | { | 
| 86 | 0 |     const auto& it = mapSigHashTypes.find(sighash_type); | 
| 87 | 0 |     if (it == mapSigHashTypes.end()) return ""; | 
| 88 | 0 |     return it->second; | 
| 89 | 0 | } | 
| 90 |  |  | 
| 91 |  | /** | 
| 92 |  |  * Create the assembly string representation of a CScript object. | 
| 93 |  |  * @param[in] script    CScript object to convert into the asm string representation. | 
| 94 |  |  * @param[in] fAttemptSighashDecode    Whether to attempt to decode sighash types on data within the script that matches the format | 
| 95 |  |  *                                     of a signature. Only pass true for scripts you believe could contain signatures. For example, | 
| 96 |  |  *                                     pass false, or omit the this argument (defaults to false), for scriptPubKeys. | 
| 97 |  |  */ | 
| 98 |  | std::string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode) | 
| 99 | 0 | { | 
| 100 | 0 |     std::string str; | 
| 101 | 0 |     opcodetype opcode; | 
| 102 | 0 |     std::vector<unsigned char> vch; | 
| 103 | 0 |     CScript::const_iterator pc = script.begin(); | 
| 104 | 0 |     while (pc < script.end()) { | 
| 105 | 0 |         if (!str.empty()) { | 
| 106 | 0 |             str += " "; | 
| 107 | 0 |         } | 
| 108 | 0 |         if (!script.GetOp(pc, opcode, vch)) { | 
| 109 | 0 |             str += "[error]"; | 
| 110 | 0 |             return str; | 
| 111 | 0 |         } | 
| 112 | 0 |         if (0 <= opcode && opcode <= OP_PUSHDATA4) { | 
| 113 | 0 |             if (vch.size() <= static_cast<std::vector<unsigned char>::size_type>(4)) { | 
| 114 | 0 |                 str += strprintf("%d", CScriptNum(vch, false).getint()); | 
| 115 | 0 |             } else { | 
| 116 |  |                 // the IsUnspendable check makes sure not to try to decode OP_RETURN data that may match the format of a signature | 
| 117 | 0 |                 if (fAttemptSighashDecode && !script.IsUnspendable()) { | 
| 118 | 0 |                     std::string strSigHashDecode; | 
| 119 |  |                     // goal: only attempt to decode a defined sighash type from data that looks like a signature within a scriptSig. | 
| 120 |  |                     // this won't decode correctly formatted public keys in Pubkey or Multisig scripts due to | 
| 121 |  |                     // the restrictions on the pubkey formats (see IsCompressedOrUncompressedPubKey) being incongruous with the | 
| 122 |  |                     // checks in CheckSignatureEncoding. | 
| 123 | 0 |                     if (CheckSignatureEncoding(vch, SCRIPT_VERIFY_STRICTENC, nullptr)) { | 
| 124 | 0 |                         const unsigned char chSigHashType = vch.back(); | 
| 125 | 0 |                         const auto it = mapSigHashTypes.find(chSigHashType); | 
| 126 | 0 |                         if (it != mapSigHashTypes.end()) { | 
| 127 | 0 |                             strSigHashDecode = "[" + it->second + "]"; | 
| 128 | 0 |                             vch.pop_back(); // remove the sighash type byte. it will be replaced by the decode. | 
| 129 | 0 |                         } | 
| 130 | 0 |                     } | 
| 131 | 0 |                     str += HexStr(vch) + strSigHashDecode; | 
| 132 | 0 |                 } else { | 
| 133 | 0 |                     str += HexStr(vch); | 
| 134 | 0 |                 } | 
| 135 | 0 |             } | 
| 136 | 0 |         } else { | 
| 137 | 0 |             str += GetOpName(opcode); | 
| 138 | 0 |         } | 
| 139 | 0 |     } | 
| 140 | 0 |     return str; | 
| 141 | 0 | } | 
| 142 |  |  | 
| 143 |  | std::string EncodeHexTx(const CTransaction& tx) | 
| 144 | 0 | { | 
| 145 | 0 |     DataStream ssTx; | 
| 146 | 0 |     ssTx << TX_WITH_WITNESS(tx); | 
| 147 | 0 |     return HexStr(ssTx); | 
| 148 | 0 | } | 
| 149 |  |  | 
| 150 |  | void ScriptToUniv(const CScript& script, UniValue& out, bool include_hex, bool include_address, const SigningProvider* provider) | 
| 151 | 0 | { | 
| 152 | 0 |     CTxDestination address; | 
| 153 |  | 
 | 
| 154 | 0 |     out.pushKV("asm", ScriptToAsmStr(script)); | 
| 155 | 0 |     if (include_address) { | 
| 156 | 0 |         out.pushKV("desc", InferDescriptor(script, provider ? *provider : DUMMY_SIGNING_PROVIDER)->ToString()); | 
| 157 | 0 |     } | 
| 158 | 0 |     if (include_hex) { | 
| 159 | 0 |         out.pushKV("hex", HexStr(script)); | 
| 160 | 0 |     } | 
| 161 |  | 
 | 
| 162 | 0 |     std::vector<std::vector<unsigned char>> solns; | 
| 163 | 0 |     const TxoutType type{Solver(script, solns)}; | 
| 164 |  | 
 | 
| 165 | 0 |     if (include_address && ExtractDestination(script, address) && type != TxoutType::PUBKEY) { | 
| 166 | 0 |         out.pushKV("address", EncodeDestination(address)); | 
| 167 | 0 |     } | 
| 168 | 0 |     out.pushKV("type", GetTxnOutputType(type)); | 
| 169 | 0 | } | 
| 170 |  |  | 
| 171 |  | void TxToUniv(const CTransaction& tx, const uint256& block_hash, UniValue& entry, bool include_hex, const CTxUndo* txundo, TxVerbosity verbosity) | 
| 172 | 0 | { | 
| 173 | 0 |     CHECK_NONFATAL(verbosity >= TxVerbosity::SHOW_DETAILS); | 
| 174 |  | 
 | 
| 175 | 0 |     entry.pushKV("txid", tx.GetHash().GetHex()); | 
| 176 | 0 |     entry.pushKV("hash", tx.GetWitnessHash().GetHex()); | 
| 177 | 0 |     entry.pushKV("version", tx.version); | 
| 178 | 0 |     entry.pushKV("size", tx.GetTotalSize()); | 
| 179 | 0 |     entry.pushKV("vsize", (GetTransactionWeight(tx) + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR); | 
| 180 | 0 |     entry.pushKV("weight", GetTransactionWeight(tx)); | 
| 181 | 0 |     entry.pushKV("locktime", (int64_t)tx.nLockTime); | 
| 182 |  | 
 | 
| 183 | 0 |     UniValue vin{UniValue::VARR}; | 
| 184 | 0 |     vin.reserve(tx.vin.size()); | 
| 185 |  |  | 
| 186 |  |     // If available, use Undo data to calculate the fee. Note that txundo == nullptr | 
| 187 |  |     // for coinbase transactions and for transactions where undo data is unavailable. | 
| 188 | 0 |     const bool have_undo = txundo != nullptr; | 
| 189 | 0 |     CAmount amt_total_in = 0; | 
| 190 | 0 |     CAmount amt_total_out = 0; | 
| 191 |  | 
 | 
| 192 | 0 |     for (unsigned int i = 0; i < tx.vin.size(); i++) { | 
| 193 | 0 |         const CTxIn& txin = tx.vin[i]; | 
| 194 | 0 |         UniValue in(UniValue::VOBJ); | 
| 195 | 0 |         if (tx.IsCoinBase()) { | 
| 196 | 0 |             in.pushKV("coinbase", HexStr(txin.scriptSig)); | 
| 197 | 0 |         } else { | 
| 198 | 0 |             in.pushKV("txid", txin.prevout.hash.GetHex()); | 
| 199 | 0 |             in.pushKV("vout", (int64_t)txin.prevout.n); | 
| 200 | 0 |             UniValue o(UniValue::VOBJ); | 
| 201 | 0 |             o.pushKV("asm", ScriptToAsmStr(txin.scriptSig, true)); | 
| 202 | 0 |             o.pushKV("hex", HexStr(txin.scriptSig)); | 
| 203 | 0 |             in.pushKV("scriptSig", std::move(o)); | 
| 204 | 0 |         } | 
| 205 | 0 |         if (!tx.vin[i].scriptWitness.IsNull()) { | 
| 206 | 0 |             UniValue txinwitness(UniValue::VARR); | 
| 207 | 0 |             txinwitness.reserve(tx.vin[i].scriptWitness.stack.size()); | 
| 208 | 0 |             for (const auto& item : tx.vin[i].scriptWitness.stack) { | 
| 209 | 0 |                 txinwitness.push_back(HexStr(item)); | 
| 210 | 0 |             } | 
| 211 | 0 |             in.pushKV("txinwitness", std::move(txinwitness)); | 
| 212 | 0 |         } | 
| 213 | 0 |         if (have_undo) { | 
| 214 | 0 |             const Coin& prev_coin = txundo->vprevout[i]; | 
| 215 | 0 |             const CTxOut& prev_txout = prev_coin.out; | 
| 216 |  | 
 | 
| 217 | 0 |             amt_total_in += prev_txout.nValue; | 
| 218 |  | 
 | 
| 219 | 0 |             if (verbosity == TxVerbosity::SHOW_DETAILS_AND_PREVOUT) { | 
| 220 | 0 |                 UniValue o_script_pub_key(UniValue::VOBJ); | 
| 221 | 0 |                 ScriptToUniv(prev_txout.scriptPubKey, /*out=*/o_script_pub_key, /*include_hex=*/true, /*include_address=*/true); | 
| 222 |  | 
 | 
| 223 | 0 |                 UniValue p(UniValue::VOBJ); | 
| 224 | 0 |                 p.pushKV("generated", bool(prev_coin.fCoinBase)); | 
| 225 | 0 |                 p.pushKV("height", uint64_t(prev_coin.nHeight)); | 
| 226 | 0 |                 p.pushKV("value", ValueFromAmount(prev_txout.nValue)); | 
| 227 | 0 |                 p.pushKV("scriptPubKey", std::move(o_script_pub_key)); | 
| 228 | 0 |                 in.pushKV("prevout", std::move(p)); | 
| 229 | 0 |             } | 
| 230 | 0 |         } | 
| 231 | 0 |         in.pushKV("sequence", (int64_t)txin.nSequence); | 
| 232 | 0 |         vin.push_back(std::move(in)); | 
| 233 | 0 |     } | 
| 234 | 0 |     entry.pushKV("vin", std::move(vin)); | 
| 235 |  | 
 | 
| 236 | 0 |     UniValue vout(UniValue::VARR); | 
| 237 | 0 |     vout.reserve(tx.vout.size()); | 
| 238 | 0 |     for (unsigned int i = 0; i < tx.vout.size(); i++) { | 
| 239 | 0 |         const CTxOut& txout = tx.vout[i]; | 
| 240 |  | 
 | 
| 241 | 0 |         UniValue out(UniValue::VOBJ); | 
| 242 |  | 
 | 
| 243 | 0 |         out.pushKV("value", ValueFromAmount(txout.nValue)); | 
| 244 | 0 |         out.pushKV("n", (int64_t)i); | 
| 245 |  | 
 | 
| 246 | 0 |         UniValue o(UniValue::VOBJ); | 
| 247 | 0 |         ScriptToUniv(txout.scriptPubKey, /*out=*/o, /*include_hex=*/true, /*include_address=*/true); | 
| 248 | 0 |         out.pushKV("scriptPubKey", std::move(o)); | 
| 249 | 0 |         vout.push_back(std::move(out)); | 
| 250 |  | 
 | 
| 251 | 0 |         if (have_undo) { | 
| 252 | 0 |             amt_total_out += txout.nValue; | 
| 253 | 0 |         } | 
| 254 | 0 |     } | 
| 255 | 0 |     entry.pushKV("vout", std::move(vout)); | 
| 256 |  | 
 | 
| 257 | 0 |     if (have_undo) { | 
| 258 | 0 |         const CAmount fee = amt_total_in - amt_total_out; | 
| 259 | 0 |         CHECK_NONFATAL(MoneyRange(fee)); | 
| 260 | 0 |         entry.pushKV("fee", ValueFromAmount(fee)); | 
| 261 | 0 |     } | 
| 262 |  | 
 | 
| 263 | 0 |     if (!block_hash.IsNull()) { | 
| 264 | 0 |         entry.pushKV("blockhash", block_hash.GetHex()); | 
| 265 | 0 |     } | 
| 266 |  | 
 | 
| 267 | 0 |     if (include_hex) { | 
| 268 | 0 |         entry.pushKV("hex", EncodeHexTx(tx)); // The hex-encoded transaction. Used the name "hex" to be consistent with the verbose output of "getrawtransaction". | 
| 269 | 0 |     } | 
| 270 | 0 | } |