static void MutateTxSign(CMutableTransaction& tx, const string& flagStr) { int nHashType = SIGHASH_ALL; if (flagStr.size() > 0) if (!findSighashFlags(nHashType, flagStr)) throw runtime_error("unknown sighash flag/sign option"); vector<CTransaction> txVariants; txVariants.push_back(tx); // mergedTx will end up with all the signatures; it // starts as a clone of the raw tx: CMutableTransaction mergedTx(txVariants[0]); bool fComplete = true; CCoinsView viewDummy; CCoinsViewCache view(viewDummy); if (!registers.count("privatekeys")) throw runtime_error("privatekeys register variable must be set."); bool fGivenKeys = false; CBasicKeyStore tempKeystore; UniValue keysObj = registers["privatekeys"]; fGivenKeys = true; for (unsigned int kidx = 0; kidx < keysObj.count(); kidx++) { if (!keysObj[kidx].isStr()) throw runtime_error("privatekey not a string"); CBitcoinSecret vchSecret; bool fGood = vchSecret.SetString(keysObj[kidx].getValStr()); if (!fGood) throw runtime_error("privatekey not valid"); CKey key = vchSecret.GetKey(); tempKeystore.AddKey(key); } // Add previous txouts given in the RPC call: if (!registers.count("prevtxs")) throw runtime_error("prevtxs register variable must be set."); UniValue prevtxsObj = registers["privatekeys"]; { for (unsigned int previdx = 0; previdx < prevtxsObj.count(); previdx++) { UniValue prevOut = prevtxsObj[previdx]; if (!prevOut.isObject()) throw runtime_error("expected prevtxs internal object"); map<string,UniValue::VType> types = map_list_of("txid", UniValue::VSTR)("vout",UniValue::VNUM)("scriptPubKey",UniValue::VSTR); if (!prevOut.checkObject(types)) throw runtime_error("prevtxs internal object typecheck fail"); uint256 txid = ParseHashUV(prevOut, "txid"); int nOut = atoi(prevOut["vout"].getValStr()); if (nOut < 0) throw runtime_error("vout must be positive"); vector<unsigned char> pkData(ParseHexUV(prevOut, "scriptPubKey")); CScript scriptPubKey(pkData.begin(), pkData.end()); CCoins coins; if (view.GetCoins(txid, coins)) { if (coins.IsAvailable(nOut) && coins.vout[nOut].scriptPubKey != scriptPubKey) { string err("Previous output scriptPubKey mismatch:\n"); err = err + coins.vout[nOut].scriptPubKey.ToString() + "\nvs:\n"+ scriptPubKey.ToString(); throw runtime_error(err); } // what todo if txid is known, but the actual output isn't? } if ((unsigned int)nOut >= coins.vout.size()) coins.vout.resize(nOut+1); coins.vout[nOut].scriptPubKey = scriptPubKey; coins.vout[nOut].nValue = 0; // we don't know the actual output value view.SetCoins(txid, coins); // if redeemScript given and private keys given, // add redeemScript to the tempKeystore so it can be signed: if (fGivenKeys && scriptPubKey.IsPayToScriptHash() && prevOut.exists("redeemScript")) { UniValue v = prevOut["redeemScript"]; vector<unsigned char> rsData(ParseHexUV(v, "redeemScript")); CScript redeemScript(rsData.begin(), rsData.end()); tempKeystore.AddCScript(redeemScript); } } } const CKeyStore& keystore = tempKeystore; bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE); // Sign what we can: for (unsigned int i = 0; i < mergedTx.vin.size(); i++) { CTxIn& txin = mergedTx.vin[i]; CCoins coins; if (!view.GetCoins(txin.prevout.hash, coins) || !coins.IsAvailable(txin.prevout.n)) { fComplete = false; continue; } const CScript& prevPubKey = coins.vout[txin.prevout.n].scriptPubKey; txin.scriptSig.clear(); // Only sign SIGHASH_SINGLE if there's a corresponding output: if (!fHashSingle || (i < mergedTx.vout.size())) SignSignature(keystore, prevPubKey, mergedTx, i, nHashType); // ... and merge in other signatures: BOOST_FOREACH(const CTransaction& txv, txVariants) { txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig); } if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, STANDARD_SCRIPT_VERIFY_FLAGS, 0)) fComplete = false; }
static bool rest_getutxos(AcceptedConnection* conn, const std::string& strURIPart, const std::string& strRequest, const std::map<std::string, std::string>& mapHeaders, bool fRun) { vector<string> params; enum RetFormat rf = ParseDataFormat(params, strURIPart); vector<string> uriParts; if (params.size() > 0 && params[0].length() > 1) { std::string strUriParams = params[0].substr(1); boost::split(uriParts, strUriParams, boost::is_any_of("/")); } // throw exception in case of a empty request if (strRequest.length() == 0 && uriParts.size() == 0) throw RESTERR(HTTP_INTERNAL_SERVER_ERROR, "Error: empty request"); bool fInputParsed = false; bool fCheckMemPool = false; vector<COutPoint> vOutPoints; // parse/deserialize input // input-format = output-format, rest/getutxos/bin requires binary input, gives binary output, ... if (uriParts.size() > 0) { //inputs is sent over URI scheme (/rest/getutxos/checkmempool/txid1-n/txid2-n/...) if (uriParts.size() > 0 && uriParts[0] == "checkmempool") fCheckMemPool = true; for (size_t i = (fCheckMemPool) ? 1 : 0; i < uriParts.size(); i++) { uint256 txid; int32_t nOutput; std::string strTxid = uriParts[i].substr(0, uriParts[i].find("-")); std::string strOutput = uriParts[i].substr(uriParts[i].find("-")+1); if (!ParseInt32(strOutput, &nOutput) || !IsHex(strTxid)) throw RESTERR(HTTP_INTERNAL_SERVER_ERROR, "Parse error"); txid.SetHex(strTxid); vOutPoints.push_back(COutPoint(txid, (uint32_t)nOutput)); } if (vOutPoints.size() > 0) fInputParsed = true; else throw RESTERR(HTTP_INTERNAL_SERVER_ERROR, "Error: empty request"); } string strRequestMutable = strRequest; //convert const string to string for allowing hex to bin converting switch (rf) { case RF_HEX: { // convert hex to bin, continue then with bin part std::vector<unsigned char> strRequestV = ParseHex(strRequest); strRequestMutable.assign(strRequestV.begin(), strRequestV.end()); } case RF_BINARY: { try { //deserialize only if user sent a request if (strRequestMutable.size() > 0) { if (fInputParsed) //don't allow sending input over URI and HTTP RAW DATA throw RESTERR(HTTP_INTERNAL_SERVER_ERROR, "Combination of URI scheme inputs and raw post data is not allowed"); CDataStream oss(SER_NETWORK, PROTOCOL_VERSION); oss << strRequestMutable; oss >> fCheckMemPool; oss >> vOutPoints; } } catch (const std::ios_base::failure& e) { // abort in case of unreadable binary data throw RESTERR(HTTP_INTERNAL_SERVER_ERROR, "Parse error"); } break; } case RF_JSON: { if (!fInputParsed) throw RESTERR(HTTP_INTERNAL_SERVER_ERROR, "Error: empty request"); break; } default: { throw RESTERR(HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")"); } } // limit max outpoints if (vOutPoints.size() > MAX_GETUTXOS_OUTPOINTS) throw RESTERR(HTTP_INTERNAL_SERVER_ERROR, strprintf("Error: max outpoints exceeded (max: %d, tried: %d)", MAX_GETUTXOS_OUTPOINTS, vOutPoints.size())); // check spentness and form a bitmap (as well as a JSON capable human-readble string representation) vector<unsigned char> bitmap; vector<CCoin> outs; std::string bitmapStringRepresentation; boost::dynamic_bitset<unsigned char> hits(vOutPoints.size()); { LOCK2(cs_main, mempool.cs); CCoinsView viewDummy; CCoinsViewCache view(&viewDummy); CCoinsViewCache& viewChain = *pcoinsTip; CCoinsViewMemPool viewMempool(&viewChain, mempool); if (fCheckMemPool) view.SetBackend(viewMempool); // switch cache backend to db+mempool in case user likes to query mempool for (size_t i = 0; i < vOutPoints.size(); i++) { CCoins coins; uint256 hash = vOutPoints[i].hash; if (view.GetCoins(hash, coins)) { mempool.pruneSpent(hash, coins); if (coins.IsAvailable(vOutPoints[i].n)) { hits[i] = true; // Safe to index into vout here because IsAvailable checked if it's off the end of the array, or if // n is valid but points to an already spent output (IsNull). CCoin coin; coin.nTxVer = coins.nVersion; coin.nHeight = coins.nHeight; coin.out = coins.vout.at(vOutPoints[i].n); assert(!coin.out.IsNull()); outs.push_back(coin); } } bitmapStringRepresentation.append(hits[i] ? "1" : "0"); // form a binary string representation (human-readable for json output) } } boost::to_block_range(hits, std::back_inserter(bitmap)); switch (rf) { case RF_BINARY: { // serialize data // use exact same output as mentioned in Bip64 CDataStream ssGetUTXOResponse(SER_NETWORK, PROTOCOL_VERSION); ssGetUTXOResponse << chainActive.Height() << chainActive.Tip()->GetBlockHash() << bitmap << outs; string ssGetUTXOResponseString = ssGetUTXOResponse.str(); conn->stream() << HTTPReplyHeader(HTTP_OK, fRun, ssGetUTXOResponseString.size(), "application/octet-stream") << ssGetUTXOResponseString << std::flush; return true; } case RF_HEX: { CDataStream ssGetUTXOResponse(SER_NETWORK, PROTOCOL_VERSION); ssGetUTXOResponse << chainActive.Height() << chainActive.Tip()->GetBlockHash() << bitmap << outs; string strHex = HexStr(ssGetUTXOResponse.begin(), ssGetUTXOResponse.end()) + "\n"; conn->stream() << HTTPReply(HTTP_OK, strHex, fRun, false, "text/plain") << std::flush; return true; } case RF_JSON: { Object objGetUTXOResponse; // pack in some essentials // use more or less the same output as mentioned in Bip64 objGetUTXOResponse.push_back(Pair("chainHeight", chainActive.Height())); objGetUTXOResponse.push_back(Pair("chaintipHash", chainActive.Tip()->GetBlockHash().GetHex())); objGetUTXOResponse.push_back(Pair("bitmap", bitmapStringRepresentation)); Array utxos; BOOST_FOREACH (const CCoin& coin, outs) { Object utxo; utxo.push_back(Pair("txvers", (int32_t)coin.nTxVer)); utxo.push_back(Pair("height", (int32_t)coin.nHeight)); utxo.push_back(Pair("value", ValueFromAmount(coin.out.nValue))); // include the script in a json output Object o; ScriptPubKeyToJSON(coin.out.scriptPubKey, o, true); utxo.push_back(Pair("scriptPubKey", o)); utxos.push_back(utxo); } objGetUTXOResponse.push_back(Pair("utxos", utxos)); // return json string string strJSON = write_string(Value(objGetUTXOResponse), false) + "\n"; conn->stream() << HTTPReply(HTTP_OK, strJSON, fRun) << std::flush; return true; } default: { throw RESTERR(HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")"); } }
void MultisigDialog::on_signTransactionButton_clicked() { ui->signedTransaction->clear(); if(!model) return; CWallet *wallet = model->getWallet(); // Decode the raw transaction std::vector<unsigned char> txData(ParseHex(ui->transaction->text().toStdString())); CDataStream ss(txData, SER_NETWORK, PROTOCOL_VERSION); CTransaction tx; try { ss >> tx; } catch(std::exception &e) { return; } CTransaction mergedTx(tx); // Fetch previous transactions (inputs) // duplicated in rpcrawtransaction.cpp:389 CCoinsView viewDummy; CCoinsViewCache view(viewDummy); { LOCK(mempool.cs); CCoinsViewCache &viewChain = *pcoinsTip; CCoinsViewMemPool viewMempool(viewChain, mempool); view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view BOOST_FOREACH(const CTxIn& txin, mergedTx.vin) { const uint256& prevHash = txin.prevout.hash; CCoins coins; view.GetCoins(prevHash, coins); // this is certainly allowed to fail } view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long } // Add the redeem scripts to the wallet keystore for(int i = 0; i < ui->inputs->count(); i++) { MultisigInputEntry *entry = qobject_cast<MultisigInputEntry *>(ui->inputs->itemAt(i)->widget()); if(entry) { QString redeemScriptStr = entry->getRedeemScript(); if(redeemScriptStr.size() > 0) { std::vector<unsigned char> scriptData(ParseHex(redeemScriptStr.toStdString())); CScript redeemScript(scriptData.begin(), scriptData.end()); wallet->AddCScript(redeemScript); } } } WalletModel::UnlockContext ctx(model->requestUnlock()); if(!ctx.isValid()) return; // Sign what we can: // mostly like rpcrawtransaction:503 bool fComplete = true; // Sign what we can: for (unsigned int i = 0; i < mergedTx.vin.size(); i++) { CTxIn& txin = mergedTx.vin[i]; CCoins coins; if (!view.GetCoins(txin.prevout.hash, coins) || !coins.IsAvailable(txin.prevout.n)) { fComplete = false; continue; } const CScript& prevPubKey = coins.vout[txin.prevout.n].scriptPubKey; txin.scriptSig.clear(); SignSignature(*wallet, prevPubKey, mergedTx, i, SIGHASH_ALL); txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, tx.vin[i].scriptSig); if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, 0)) fComplete = false; } CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); ssTx << mergedTx; ui->signedTransaction->setText(HexStr(ssTx.begin(), ssTx.end()).c_str()); if(fComplete) { ui->statusLabel->setText(tr("Transaction signature is complete")); ui->sendTransactionButton->setEnabled(true); } else { ui->statusLabel->setText(tr("Transaction is NOT completely signed")); ui->sendTransactionButton->setEnabled(false); } }