diff options
Diffstat (limited to 'src/rpcrawtransaction.cpp')
-rw-r--r-- | src/rpcrawtransaction.cpp | 141 |
1 files changed, 90 insertions, 51 deletions
diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index 4714bfdd20..e82f4ad91d 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -18,6 +18,39 @@ using namespace boost; using namespace boost::assign; using namespace json_spirit; +// +// Utilities: convert hex-encoded Values +// (throws error if not hex). +// +uint256 ParseHashV(const Value& v, string strName) +{ + string strHex; + if (v.type() == str_type) + strHex = v.get_str(); + if (!IsHex(strHex)) // Note: IsHex("") is false + throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')"); + uint256 result; + result.SetHex(strHex); + return result; +} +uint256 ParseHashO(const Object& o, string strKey) +{ + return ParseHashV(find_value(o, strKey), strKey); +} +vector<unsigned char> ParseHexV(const Value& v, string strName) +{ + string strHex; + if (v.type() == str_type) + strHex = v.get_str(); + if (!IsHex(strHex)) + throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')"); + return ParseHex(strHex); +} +vector<unsigned char> ParseHexO(const Object& o, string strKey) +{ + return ParseHexV(find_value(o, strKey), strKey); +} + void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out) { txnouttype type; @@ -109,8 +142,7 @@ Value getrawtransaction(const Array& params, bool fHelp) "If verbose is non-zero, returns an Object\n" "with information about <txid>."); - uint256 hash; - hash.SetHex(params[0].get_str()); + uint256 hash = ParseHashV(params[0], "parameter 1"); bool fVerbose = false; if (params.size() > 1) @@ -178,10 +210,10 @@ Value listunspent(const Array& params, bool fHelp) if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth) continue; - if(setAddress.size()) + if (setAddress.size()) { CTxDestination address; - if(!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) + if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) continue; if (!setAddress.count(address)) @@ -194,6 +226,17 @@ Value listunspent(const Array& params, bool fHelp) entry.push_back(Pair("txid", out.tx->GetHash().GetHex())); entry.push_back(Pair("vout", out.i)); entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end()))); + if (pk.IsPayToScriptHash()) + { + CTxDestination address; + if (ExtractDestination(pk, address)) + { + const CScriptID& hash = boost::get<const CScriptID&>(address); + CScript redeemScript; + if (pwalletMain->GetCScript(hash, redeemScript)) + entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end()))); + } + } entry.push_back(Pair("amount",ValueFromAmount(nValue))); entry.push_back(Pair("confirmations",out.nDepth)); results.push_back(entry); @@ -221,16 +264,11 @@ Value createrawtransaction(const Array& params, bool fHelp) CTransaction rawTx; - BOOST_FOREACH(Value& input, inputs) + BOOST_FOREACH(const Value& input, inputs) { const Object& o = input.get_obj(); - const Value& txid_v = find_value(o, "txid"); - if (txid_v.type() != str_type) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing txid key"); - string txid = txid_v.get_str(); - if (!IsHex(txid)) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid"); + uint256 txid = ParseHashO(o, "txid"); const Value& vout_v = find_value(o, "vout"); if (vout_v.type() != int_type) @@ -239,7 +277,7 @@ Value createrawtransaction(const Array& params, bool fHelp) if (nOutput < 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive"); - CTxIn in(COutPoint(uint256(txid), nOutput)); + CTxIn in(COutPoint(txid, nOutput)); rawTx.vin.push_back(in); } @@ -274,9 +312,7 @@ Value decoderawtransaction(const Array& params, bool fHelp) "decoderawtransaction <hex string>\n" "Return a JSON object representing the serialized, hex-encoded transaction."); - RPCTypeCheck(params, list_of(str_type)); - - vector<unsigned char> txData(ParseHex(params[0].get_str())); + vector<unsigned char> txData(ParseHexV(params[0], "argument")); CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION); CTransaction tx; try { @@ -296,7 +332,7 @@ Value signrawtransaction(const Array& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 4) throw runtime_error( - "signrawtransaction <hex string> [{\"txid\":txid,\"vout\":n,\"scriptPubKey\":hex},...] [<privatekey1>,...] [sighashtype=\"ALL\"]\n" + "signrawtransaction <hex string> [{\"txid\":txid,\"vout\":n,\"scriptPubKey\":hex,\"redeemScript\":hex},...] [<privatekey1>,...] [sighashtype=\"ALL\"]\n" "Sign inputs for raw transaction (serialized, hex-encoded).\n" "Second optional argument (may be null) is an array of previous transaction outputs that\n" "this transaction depends on but may not yet be in the block chain.\n" @@ -311,7 +347,7 @@ Value signrawtransaction(const Array& params, bool fHelp) RPCTypeCheck(params, list_of(str_type)(array_type)(array_type)(str_type), true); - vector<unsigned char> txData(ParseHex(params[0].get_str())); + vector<unsigned char> txData(ParseHexV(params[0], "argument 1")); CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION); vector<CTransaction> txVariants; while (!ssData.empty()) @@ -352,6 +388,28 @@ Value signrawtransaction(const Array& params, bool fHelp) view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long } + bool fGivenKeys = false; + CBasicKeyStore tempKeystore; + if (params.size() > 2 && params[2].type() != null_type) + { + fGivenKeys = true; + Array keys = params[2].get_array(); + BOOST_FOREACH(Value k, keys) + { + CBitcoinSecret vchSecret; + bool fGood = vchSecret.SetString(k.get_str()); + if (!fGood) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key"); + CKey key; + bool fCompressed; + CSecret secret = vchSecret.GetSecret(fCompressed); + key.SetSecret(secret, fCompressed); + tempKeystore.AddKey(key); + } + } + else + EnsureWalletIsUnlocked(); + // Add previous txouts given in the RPC call: if (params.size() > 1 && params[1].type() != null_type) { @@ -363,22 +421,15 @@ Value signrawtransaction(const Array& params, bool fHelp) Object prevOut = p.get_obj(); - RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type)); + RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type)("redeemScript",str_type)); - string txidHex = find_value(prevOut, "txid").get_str(); - if (!IsHex(txidHex)) - throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "txid must be hexadecimal"); - uint256 txid; - txid.SetHex(txidHex); + uint256 txid = ParseHashO(prevOut, "txid"); int nOut = find_value(prevOut, "vout").get_int(); if (nOut < 0) throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive"); - string pkHex = find_value(prevOut, "scriptPubKey").get_str(); - if (!IsHex(pkHex)) - throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "scriptPubKey must be hexadecimal"); - vector<unsigned char> pkData(ParseHex(pkHex)); + vector<unsigned char> pkData(ParseHexO(prevOut, "scriptPubKey")); CScript scriptPubKey(pkData.begin(), pkData.end()); CCoins coins; @@ -391,33 +442,23 @@ Value signrawtransaction(const Array& params, bool fHelp) } // 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); - } - } - bool fGivenKeys = false; - CBasicKeyStore tempKeystore; - if (params.size() > 2 && params[2].type() != null_type) - { - fGivenKeys = true; - Array keys = params[2].get_array(); - BOOST_FOREACH(Value k, keys) - { - CBitcoinSecret vchSecret; - bool fGood = vchSecret.SetString(k.get_str()); - if (!fGood) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,"Invalid private key"); - CKey key; - bool fCompressed; - CSecret secret = vchSecret.GetSecret(fCompressed); - key.SetSecret(secret, fCompressed); - tempKeystore.AddKey(key); + // if redeemScript given and not using the local wallet (private keys + // given), add redeemScript to the tempKeystore so it can be signed: + Value v = find_value(prevOut, "redeemScript"); + if (fGivenKeys && scriptPubKey.IsPayToScriptHash() && !(v == Value::null)) + { + vector<unsigned char> rsData(ParseHexV(v, "redeemScript")); + CScript redeemScript(rsData.begin(), rsData.end()); + tempKeystore.AddCScript(redeemScript); + } } } - else - EnsureWalletIsUnlocked(); const CKeyStore& keystore = (fGivenKeys ? tempKeystore : *pwalletMain); @@ -484,10 +525,8 @@ Value sendrawtransaction(const Array& params, bool fHelp) "sendrawtransaction <hex string>\n" "Submits raw transaction (serialized, hex-encoded) to local node and network."); - RPCTypeCheck(params, list_of(str_type)); - // parse hex string from parameter - vector<unsigned char> txData(ParseHex(params[0].get_str())); + vector<unsigned char> txData(ParseHexV(params[0], "parameter")); CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION); CTransaction tx; |