Branch data Line data Source code
# 1 : : // Copyright (c) 2010 Satoshi Nakamoto
# 2 : : // Copyright (c) 2009-2020 The Bitcoin Core developers
# 3 : : // Distributed under the MIT software license, see the accompanying
# 4 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
# 5 : :
# 6 : : #include <rpc/rawtransaction_util.h>
# 7 : :
# 8 : : #include <coins.h>
# 9 : : #include <core_io.h>
# 10 : : #include <key_io.h>
# 11 : : #include <policy/policy.h>
# 12 : : #include <primitives/transaction.h>
# 13 : : #include <rpc/request.h>
# 14 : : #include <rpc/util.h>
# 15 : : #include <script/sign.h>
# 16 : : #include <script/signingprovider.h>
# 17 : : #include <tinyformat.h>
# 18 : : #include <univalue.h>
# 19 : : #include <util/rbf.h>
# 20 : : #include <util/strencodings.h>
# 21 : :
# 22 : : CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, bool rbf)
# 23 : 1538 : {
# 24 [ + + ]: 1538 : if (outputs_in.isNull()) {
# 25 : 2 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, output argument must be non-null");
# 26 : 2 : }
# 27 : :
# 28 : 1536 : UniValue inputs;
# 29 [ + + ]: 1536 : if (inputs_in.isNull()) {
# 30 : 210 : inputs = UniValue::VARR;
# 31 : 1326 : } else {
# 32 : 1326 : inputs = inputs_in.get_array();
# 33 : 1326 : }
# 34 : :
# 35 : 1536 : const bool outputs_is_obj = outputs_in.isObject();
# 36 [ + + ]: 1536 : UniValue outputs = outputs_is_obj ? outputs_in.get_obj() : outputs_in.get_array();
# 37 : :
# 38 : 1536 : CMutableTransaction rawTx;
# 39 : :
# 40 [ + + ]: 1536 : if (!locktime.isNull()) {
# 41 : 228 : int64_t nLockTime = locktime.get_int64();
# 42 [ + + ][ + + ]: 228 : if (nLockTime < 0 || nLockTime > LOCKTIME_MAX)
# 43 : 4 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, locktime out of range");
# 44 : 224 : rawTx.nLockTime = nLockTime;
# 45 : 224 : }
# 46 : :
# 47 [ + + ]: 8426 : for (unsigned int idx = 0; idx < inputs.size(); idx++) {
# 48 : 6906 : const UniValue& input = inputs[idx];
# 49 : 6906 : const UniValue& o = input.get_obj();
# 50 : :
# 51 : 6906 : uint256 txid = ParseHashO(o, "txid");
# 52 : :
# 53 : 6906 : const UniValue& vout_v = find_value(o, "vout");
# 54 [ + + ]: 6906 : if (!vout_v.isNum())
# 55 : 4 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key");
# 56 : 6902 : int nOutput = vout_v.get_int();
# 57 [ + + ]: 6902 : if (nOutput < 0)
# 58 : 2 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout cannot be negative");
# 59 : :
# 60 : 6900 : uint32_t nSequence;
# 61 [ + + ]: 6900 : if (rbf) {
# 62 : 69 : nSequence = MAX_BIP125_RBF_SEQUENCE; /* CTxIn::SEQUENCE_FINAL - 2 */
# 63 [ + + ]: 6831 : } else if (rawTx.nLockTime) {
# 64 : 17 : nSequence = CTxIn::SEQUENCE_FINAL - 1;
# 65 : 6814 : } else {
# 66 : 6814 : nSequence = CTxIn::SEQUENCE_FINAL;
# 67 : 6814 : }
# 68 : :
# 69 : : // set the sequence number if passed in the parameters object
# 70 : 6900 : const UniValue& sequenceObj = find_value(o, "sequence");
# 71 [ + + ]: 6900 : if (sequenceObj.isNum()) {
# 72 : 58 : int64_t seqNr64 = sequenceObj.get_int64();
# 73 [ + + ][ + + ]: 58 : if (seqNr64 < 0 || seqNr64 > CTxIn::SEQUENCE_FINAL) {
# 74 : 6 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, sequence number is out of range");
# 75 : 52 : } else {
# 76 : 52 : nSequence = (uint32_t)seqNr64;
# 77 : 52 : }
# 78 : 58 : }
# 79 : :
# 80 : 6900 : CTxIn in(COutPoint(txid, nOutput), CScript(), nSequence);
# 81 : :
# 82 : 6894 : rawTx.vin.push_back(in);
# 83 : 6894 : }
# 84 : :
# 85 [ + + ]: 1532 : if (!outputs_is_obj) {
# 86 : : // Translate array of key-value pairs into dict
# 87 : 364 : UniValue outputs_dict = UniValue(UniValue::VOBJ);
# 88 [ + + ]: 736 : for (size_t i = 0; i < outputs.size(); ++i) {
# 89 : 376 : const UniValue& output = outputs[i];
# 90 [ + + ]: 376 : if (!output.isObject()) {
# 91 : 2 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, key-value pair not an object as expected");
# 92 : 2 : }
# 93 [ + + ]: 374 : if (output.size() != 1) {
# 94 : 2 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, key-value pair must contain exactly one key");
# 95 : 2 : }
# 96 : 372 : outputs_dict.pushKVs(output);
# 97 : 372 : }
# 98 : 364 : outputs = std::move(outputs_dict);
# 99 : 360 : }
# 100 : :
# 101 : : // Duplicate checking
# 102 : 1520 : std::set<CTxDestination> destinations;
# 103 : 1516 : bool has_data{false};
# 104 : :
# 105 [ + + ]: 7939 : for (const std::string& name_ : outputs.getKeys()) {
# 106 [ + + ]: 7939 : if (name_ == "data") {
# 107 [ + + ]: 28 : if (has_data) {
# 108 : 4 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, duplicate key: data");
# 109 : 4 : }
# 110 : 24 : has_data = true;
# 111 : 24 : std::vector<unsigned char> data = ParseHexV(outputs[name_].getValStr(), "Data");
# 112 : :
# 113 : 24 : CTxOut out(0, CScript() << OP_RETURN << data);
# 114 : 24 : rawTx.vout.push_back(out);
# 115 : 7911 : } else {
# 116 : 7911 : CTxDestination destination = DecodeDestination(name_);
# 117 [ + + ]: 7911 : if (!IsValidDestination(destination)) {
# 118 : 4 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ") + name_);
# 119 : 4 : }
# 120 : :
# 121 [ + + ]: 7907 : if (!destinations.insert(destination).second) {
# 122 : 4 : throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + name_);
# 123 : 4 : }
# 124 : :
# 125 : 7903 : CScript scriptPubKey = GetScriptForDestination(destination);
# 126 : 7903 : CAmount nAmount = AmountFromValue(outputs[name_]);
# 127 : :
# 128 : 7903 : CTxOut out(nAmount, scriptPubKey);
# 129 : 7903 : rawTx.vout.push_back(out);
# 130 : 7903 : }
# 131 : 7939 : }
# 132 : :
# 133 [ + + ][ - + ]: 1516 : if (rbf && rawTx.vin.size() > 0 && !SignalsOptInRBF(CTransaction(rawTx))) {
# [ + + ][ - + ]
# 134 : 0 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter combination: Sequence number(s) contradict replaceable option");
# 135 : 0 : }
# 136 : :
# 137 : 1504 : return rawTx;
# 138 : 1504 : }
# 139 : :
# 140 : : /** Pushes a JSON object for script verification or signing errors to vErrorsRet. */
# 141 : : static void TxInErrorToJSON(const CTxIn& txin, UniValue& vErrorsRet, const std::string& strMessage)
# 142 : 92 : {
# 143 : 92 : UniValue entry(UniValue::VOBJ);
# 144 : 92 : entry.pushKV("txid", txin.prevout.hash.ToString());
# 145 : 92 : entry.pushKV("vout", (uint64_t)txin.prevout.n);
# 146 : 92 : UniValue witness(UniValue::VARR);
# 147 [ + + ]: 324 : for (unsigned int i = 0; i < txin.scriptWitness.stack.size(); i++) {
# 148 : 232 : witness.push_back(HexStr(txin.scriptWitness.stack[i]));
# 149 : 232 : }
# 150 : 92 : entry.pushKV("witness", witness);
# 151 : 92 : entry.pushKV("scriptSig", HexStr(txin.scriptSig));
# 152 : 92 : entry.pushKV("sequence", (uint64_t)txin.nSequence);
# 153 : 92 : entry.pushKV("error", strMessage);
# 154 : 92 : vErrorsRet.push_back(entry);
# 155 : 92 : }
# 156 : :
# 157 : : void ParsePrevouts(const UniValue& prevTxsUnival, FillableSigningProvider* keystore, std::map<COutPoint, Coin>& coins)
# 158 : 1496 : {
# 159 [ + + ]: 1496 : if (!prevTxsUnival.isNull()) {
# 160 : 274 : UniValue prevTxs = prevTxsUnival.get_array();
# 161 [ + + ]: 489 : for (unsigned int idx = 0; idx < prevTxs.size(); ++idx) {
# 162 : 311 : const UniValue& p = prevTxs[idx];
# 163 [ - + ]: 311 : if (!p.isObject()) {
# 164 : 0 : throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}");
# 165 : 0 : }
# 166 : :
# 167 : 311 : UniValue prevOut = p.get_obj();
# 168 : :
# 169 : 311 : RPCTypeCheckObj(prevOut,
# 170 : 311 : {
# 171 : 311 : {"txid", UniValueType(UniValue::VSTR)},
# 172 : 311 : {"vout", UniValueType(UniValue::VNUM)},
# 173 : 311 : {"scriptPubKey", UniValueType(UniValue::VSTR)},
# 174 : 311 : });
# 175 : :
# 176 : 311 : uint256 txid = ParseHashO(prevOut, "txid");
# 177 : :
# 178 : 311 : int nOut = find_value(prevOut, "vout").get_int();
# 179 [ - + ]: 311 : if (nOut < 0) {
# 180 : 0 : throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout cannot be negative");
# 181 : 0 : }
# 182 : :
# 183 : 311 : COutPoint out(txid, nOut);
# 184 : 311 : std::vector<unsigned char> pkData(ParseHexO(prevOut, "scriptPubKey"));
# 185 : 311 : CScript scriptPubKey(pkData.begin(), pkData.end());
# 186 : :
# 187 : 311 : {
# 188 : 311 : auto coin = coins.find(out);
# 189 [ + + ][ - + ]: 311 : if (coin != coins.end() && !coin->second.IsSpent() && coin->second.out.scriptPubKey != scriptPubKey) {
# [ + + ][ - + ]
# 190 : 0 : std::string err("Previous output scriptPubKey mismatch:\n");
# 191 : 0 : err = err + ScriptToAsmStr(coin->second.out.scriptPubKey) + "\nvs:\n"+
# 192 : 0 : ScriptToAsmStr(scriptPubKey);
# 193 : 0 : throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
# 194 : 0 : }
# 195 : 311 : Coin newcoin;
# 196 : 311 : newcoin.out.scriptPubKey = scriptPubKey;
# 197 : 311 : newcoin.out.nValue = MAX_MONEY;
# 198 [ + + ]: 311 : if (prevOut.exists("amount")) {
# 199 : 271 : newcoin.out.nValue = AmountFromValue(find_value(prevOut, "amount"));
# 200 : 271 : }
# 201 : 311 : newcoin.nHeight = 1;
# 202 : 311 : coins[out] = std::move(newcoin);
# 203 : 311 : }
# 204 : :
# 205 : : // if redeemScript and private keys were given, add redeemScript to the keystore so it can be signed
# 206 : 311 : const bool is_p2sh = scriptPubKey.IsPayToScriptHash();
# 207 : 311 : const bool is_p2wsh = scriptPubKey.IsPayToWitnessScriptHash();
# 208 [ + + ][ + + ]: 311 : if (keystore && (is_p2sh || is_p2wsh)) {
# [ + + ]
# 209 : 202 : RPCTypeCheckObj(prevOut,
# 210 : 202 : {
# 211 : 202 : {"redeemScript", UniValueType(UniValue::VSTR)},
# 212 : 202 : {"witnessScript", UniValueType(UniValue::VSTR)},
# 213 : 202 : }, true);
# 214 : 202 : UniValue rs = find_value(prevOut, "redeemScript");
# 215 : 202 : UniValue ws = find_value(prevOut, "witnessScript");
# 216 [ + + ][ + + ]: 202 : if (rs.isNull() && ws.isNull()) {
# 217 : 24 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Missing redeemScript/witnessScript");
# 218 : 24 : }
# 219 : :
# 220 : : // work from witnessScript when possible
# 221 [ + + ]: 178 : std::vector<unsigned char> scriptData(!ws.isNull() ? ParseHexV(ws, "witnessScript") : ParseHexV(rs, "redeemScript"));
# 222 : 178 : CScript script(scriptData.begin(), scriptData.end());
# 223 : 178 : keystore->AddCScript(script);
# 224 : : // Automatically also add the P2WSH wrapped version of the script (to deal with P2SH-P2WSH).
# 225 : : // This is done for redeemScript only for compatibility, it is encouraged to use the explicit witnessScript field instead.
# 226 : 178 : CScript witness_output_script{GetScriptForDestination(WitnessV0ScriptHash(script))};
# 227 : 178 : keystore->AddCScript(witness_output_script);
# 228 : :
# 229 [ + + ][ + + ]: 178 : if (!ws.isNull() && !rs.isNull()) {
# 230 : : // if both witnessScript and redeemScript are provided,
# 231 : : // they should either be the same (for backwards compat),
# 232 : : // or the redeemScript should be the encoded form of
# 233 : : // the witnessScript (ie, for p2sh-p2wsh)
# 234 [ + + ]: 54 : if (ws.get_str() != rs.get_str()) {
# 235 : 30 : std::vector<unsigned char> redeemScriptData(ParseHexV(rs, "redeemScript"));
# 236 : 30 : CScript redeemScript(redeemScriptData.begin(), redeemScriptData.end());
# 237 [ + + ]: 30 : if (redeemScript != witness_output_script) {
# 238 : 24 : throw JSONRPCError(RPC_INVALID_PARAMETER, "redeemScript does not correspond to witnessScript");
# 239 : 24 : }
# 240 : 154 : }
# 241 : 54 : }
# 242 : :
# 243 [ + + ]: 154 : if (is_p2sh) {
# 244 : 106 : const CTxDestination p2sh{ScriptHash(script)};
# 245 : 106 : const CTxDestination p2sh_p2wsh{ScriptHash(witness_output_script)};
# 246 [ + + ]: 106 : if (scriptPubKey == GetScriptForDestination(p2sh)) {
# 247 : : // traditional p2sh; arguably an error if
# 248 : : // we got here with rs.IsNull(), because
# 249 : : // that means the p2sh script was specified
# 250 : : // via witnessScript param, but for now
# 251 : : // we'll just quietly accept it
# 252 [ + + ]: 70 : } else if (scriptPubKey == GetScriptForDestination(p2sh_p2wsh)) {
# 253 : : // p2wsh encoded as p2sh; ideally the witness
# 254 : : // script was specified in the witnessScript
# 255 : : // param, but also support specifying it via
# 256 : : // redeemScript param for backwards compat
# 257 : : // (in which case ws.IsNull() == true)
# 258 : 38 : } else {
# 259 : : // otherwise, can't generate scriptPubKey from
# 260 : : // either script, so we got unusable parameters
# 261 : 32 : throw JSONRPCError(RPC_INVALID_PARAMETER, "redeemScript/witnessScript does not match scriptPubKey");
# 262 : 32 : }
# 263 [ + - ]: 48 : } else if (is_p2wsh) {
# 264 : : // plain p2wsh; could throw an error if script
# 265 : : // was specified by redeemScript rather than
# 266 : : // witnessScript (ie, ws.IsNull() == true), but
# 267 : : // accept it for backwards compat
# 268 : 48 : const CTxDestination p2wsh{WitnessV0ScriptHash(script)};
# 269 [ + + ]: 48 : if (scriptPubKey != GetScriptForDestination(p2wsh)) {
# 270 : 16 : throw JSONRPCError(RPC_INVALID_PARAMETER, "redeemScript/witnessScript does not match scriptPubKey");
# 271 : 16 : }
# 272 : 48 : }
# 273 : 154 : }
# 274 : 311 : }
# 275 : 274 : }
# 276 : 1496 : }
# 277 : :
# 278 : : void SignTransaction(CMutableTransaction& mtx, const SigningProvider* keystore, const std::map<COutPoint, Coin>& coins, const UniValue& hashType, UniValue& result)
# 279 : 189 : {
# 280 : 189 : int nHashType = ParseSighashString(hashType);
# 281 : :
# 282 : : // Script verification errors
# 283 : 189 : std::map<int, std::string> input_errors;
# 284 : :
# 285 : 189 : bool complete = SignTransaction(mtx, keystore, coins, nHashType, input_errors);
# 286 : 189 : SignTransactionResultToJSON(mtx, complete, coins, input_errors, result);
# 287 : 189 : }
# 288 : :
# 289 : : void SignTransactionResultToJSON(CMutableTransaction& mtx, bool complete, const std::map<COutPoint, Coin>& coins, const std::map<int, std::string>& input_errors, UniValue& result)
# 290 : 1382 : {
# 291 : : // Make errors UniValue
# 292 : 1382 : UniValue vErrors(UniValue::VARR);
# 293 [ + + ]: 1382 : for (const auto& err_pair : input_errors) {
# 294 [ + + ]: 96 : if (err_pair.second == "Missing amount") {
# 295 : : // This particular error needs to be an exception for some reason
# 296 : 4 : throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing amount for %s", coins.at(mtx.vin.at(err_pair.first).prevout).out.ToString()));
# 297 : 4 : }
# 298 : 92 : TxInErrorToJSON(mtx.vin.at(err_pair.first), vErrors, err_pair.second);
# 299 : 92 : }
# 300 : :
# 301 : 1382 : result.pushKV("hex", EncodeHexTx(CTransaction(mtx)));
# 302 : 1378 : result.pushKV("complete", complete);
# 303 [ + + ]: 1378 : if (!vErrors.empty()) {
# 304 [ - + ]: 88 : if (result.exists("errors")) {
# 305 : 0 : vErrors.push_backV(result["errors"].getValues());
# 306 : 0 : }
# 307 : 88 : result.pushKV("errors", vErrors);
# 308 : 88 : }
# 309 : 1378 : }
|