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