| 413 | } |
| 414 | |
| 415 | void ParsePrevouts(const UniValue& prevTxsUnival, FillableSigningProvider* keystore, std::map<COutPoint, Coin>& coins) |
| 416 | { |
| 417 | if (!prevTxsUnival.isNull()) { |
| 418 | UniValue prevTxs = prevTxsUnival.get_array(); |
| 419 | for (unsigned int idx = 0; idx < prevTxs.size(); ++idx) { |
| 420 | const UniValue& p = prevTxs[idx]; |
| 421 | if (!p.isObject()) { |
| 422 | throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}"); |
| 423 | } |
| 424 | |
| 425 | UniValue prevOut = p.get_obj(); |
| 426 | |
| 427 | RPCTypeCheckObj(prevOut, |
| 428 | { |
| 429 | {"txid", UniValueType(UniValue::VSTR)}, |
| 430 | {"vout", UniValueType(UniValue::VNUM)}, |
| 431 | {"scriptPubKey", UniValueType(UniValue::VSTR)}, |
| 432 | }); |
| 433 | |
| 434 | uint256 txid = ParseHashO(prevOut, "txid"); |
| 435 | |
| 436 | int nOut = find_value(prevOut, "vout").get_int(); |
| 437 | if (nOut < 0) { |
| 438 | throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout cannot be negative"); |
| 439 | } |
| 440 | |
| 441 | COutPoint out(txid, nOut); |
| 442 | std::vector<unsigned char> pkData(ParseHexO(prevOut, "scriptPubKey")); |
| 443 | CScript scriptPubKey(pkData.begin(), pkData.end()); |
| 444 | |
| 445 | { |
| 446 | auto coin = coins.find(out); |
| 447 | if (coin != coins.end() && !coin->second.IsSpent() && coin->second.out.scriptPubKey != scriptPubKey) { |
| 448 | std::string err("Previous output scriptPubKey mismatch:\n"); |
| 449 | err = err + ScriptToAsmStr(coin->second.out.scriptPubKey) + "\nvs:\n"+ |
| 450 | ScriptToAsmStr(scriptPubKey); |
| 451 | throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err); |
| 452 | } |
| 453 | Coin newcoin; |
| 454 | newcoin.out.scriptPubKey = scriptPubKey; |
| 455 | newcoin.out.nValue = CConfidentialValue(MAX_MONEY); |
| 456 | if (prevOut.exists("amount")) { |
| 457 | newcoin.out.nValue = CConfidentialValue(AmountFromValue(find_value(prevOut, "amount"))); |
| 458 | } else if (prevOut.exists("amountcommitment")) { |
| 459 | // Segwit sigs require the amount commitment to be sighashed |
| 460 | newcoin.out.nValue.vchCommitment = ParseHexO(prevOut, "amountcommitment"); |
| 461 | } |
| 462 | newcoin.nHeight = 1; |
| 463 | coins[out] = std::move(newcoin); |
| 464 | } |
| 465 | |
| 466 | // if redeemScript and private keys were given, add redeemScript to the keystore so it can be signed |
| 467 | const bool is_p2sh = scriptPubKey.IsPayToScriptHash(); |
| 468 | const bool is_p2wsh = scriptPubKey.IsPayToWitnessScriptHash(); |
| 469 | if (keystore && (is_p2sh || is_p2wsh)) { |
| 470 | RPCTypeCheckObj(prevOut, |
| 471 | { |
| 472 | {"redeemScript", UniValueType(UniValue::VSTR)}, |
no test coverage detected