1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
6 #include <boost/assign/list_of.hpp>
9 #include "bitcoinrpc.h"
17 using namespace boost;
18 using namespace boost::assign;
19 using namespace json_spirit;
22 // Utilities: convert hex-encoded Values
23 // (throws error if not hex).
25 uint256 ParseHashV(const Value& v, string strName)
28 if (v.type() == str_type)
30 if (!IsHex(strHex)) // Note: IsHex("") is false
31 throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
33 result.SetHex(strHex);
36 uint256 ParseHashO(const Object& o, string strKey)
38 return ParseHashV(find_value(o, strKey), strKey);
40 vector<unsigned char> ParseHexV(const Value& v, string strName)
43 if (v.type() == str_type)
46 throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
47 return ParseHex(strHex);
49 vector<unsigned char> ParseHexO(const Object& o, string strKey)
51 return ParseHexV(find_value(o, strKey), strKey);
54 void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out)
57 vector<CTxDestination> addresses;
60 out.push_back(Pair("asm", scriptPubKey.ToString()));
61 out.push_back(Pair("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end())));
63 if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired))
65 out.push_back(Pair("type", GetTxnOutputType(TX_NONSTANDARD)));
69 out.push_back(Pair("reqSigs", nRequired));
70 out.push_back(Pair("type", GetTxnOutputType(type)));
73 BOOST_FOREACH(const CTxDestination& addr, addresses)
74 a.push_back(CBitcoinAddress(addr).ToString());
75 out.push_back(Pair("addresses", a));
78 void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry)
80 entry.push_back(Pair("txid", tx.GetHash().GetHex()));
81 entry.push_back(Pair("version", tx.nVersion));
82 entry.push_back(Pair("locktime", (boost::int64_t)tx.nLockTime));
84 BOOST_FOREACH(const CTxIn& txin, tx.vin)
88 in.push_back(Pair("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
91 in.push_back(Pair("txid", txin.prevout.hash.GetHex()));
92 in.push_back(Pair("vout", (boost::int64_t)txin.prevout.n));
94 o.push_back(Pair("asm", txin.scriptSig.ToString()));
95 o.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
96 in.push_back(Pair("scriptSig", o));
98 in.push_back(Pair("sequence", (boost::int64_t)txin.nSequence));
101 entry.push_back(Pair("vin", vin));
103 for (unsigned int i = 0; i < tx.vout.size(); i++)
105 const CTxOut& txout = tx.vout[i];
107 out.push_back(Pair("value", ValueFromAmount(txout.nValue)));
108 out.push_back(Pair("n", (boost::int64_t)i));
110 ScriptPubKeyToJSON(txout.scriptPubKey, o);
111 out.push_back(Pair("scriptPubKey", o));
114 entry.push_back(Pair("vout", vout));
118 entry.push_back(Pair("blockhash", hashBlock.GetHex()));
119 map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
120 if (mi != mapBlockIndex.end() && (*mi).second)
122 CBlockIndex* pindex = (*mi).second;
123 if (pindex->IsInMainChain())
125 entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight));
126 entry.push_back(Pair("time", (boost::int64_t)pindex->nTime));
127 entry.push_back(Pair("blocktime", (boost::int64_t)pindex->nTime));
130 entry.push_back(Pair("confirmations", 0));
135 Value getrawtransaction(const Array& params, bool fHelp)
137 if (fHelp || params.size() < 1 || params.size() > 2)
139 "getrawtransaction <txid> [verbose=0]\n"
140 "If verbose=0, returns a string that is\n"
141 "serialized, hex-encoded data for <txid>.\n"
142 "If verbose is non-zero, returns an Object\n"
143 "with information about <txid>.");
145 uint256 hash = ParseHashV(params[0], "parameter 1");
147 bool fVerbose = false;
148 if (params.size() > 1)
149 fVerbose = (params[1].get_int() != 0);
152 uint256 hashBlock = 0;
153 if (!GetTransaction(hash, tx, hashBlock, true))
154 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
156 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
158 string strHex = HexStr(ssTx.begin(), ssTx.end());
164 result.push_back(Pair("hex", strHex));
165 TxToJSON(tx, hashBlock, result);
169 Value listunspent(const Array& params, bool fHelp)
171 if (fHelp || params.size() > 3)
173 "listunspent [minconf=1] [maxconf=9999999] [\"address\",...]\n"
174 "Returns array of unspent transaction outputs\n"
175 "with between minconf and maxconf (inclusive) confirmations.\n"
176 "Optionally filtered to only include txouts paid to specified addresses.\n"
177 "Results are an array of Objects, each of which has:\n"
178 "{txid, vout, scriptPubKey, amount, confirmations}");
180 RPCTypeCheck(params, list_of(int_type)(int_type)(array_type));
183 if (params.size() > 0)
184 nMinDepth = params[0].get_int();
186 int nMaxDepth = 9999999;
187 if (params.size() > 1)
188 nMaxDepth = params[1].get_int();
190 set<CBitcoinAddress> setAddress;
191 if (params.size() > 2)
193 Array inputs = params[2].get_array();
194 BOOST_FOREACH(Value& input, inputs)
196 CBitcoinAddress address(input.get_str());
197 if (!address.IsValid())
198 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+input.get_str());
199 if (setAddress.count(address))
200 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str());
201 setAddress.insert(address);
206 vector<COutput> vecOutputs;
207 pwalletMain->AvailableCoins(vecOutputs, false);
208 BOOST_FOREACH(const COutput& out, vecOutputs)
210 if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
213 if (setAddress.size())
215 CTxDestination address;
216 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
219 if (!setAddress.count(address))
223 int64 nValue = out.tx->vout[out.i].nValue;
224 const CScript& pk = out.tx->vout[out.i].scriptPubKey;
226 entry.push_back(Pair("txid", out.tx->GetHash().GetHex()));
227 entry.push_back(Pair("vout", out.i));
228 entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end())));
229 if (pk.IsPayToScriptHash())
231 CTxDestination address;
232 if (ExtractDestination(pk, address))
234 const CScriptID& hash = boost::get<const CScriptID&>(address);
235 CScript redeemScript;
236 if (pwalletMain->GetCScript(hash, redeemScript))
237 entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end())));
240 entry.push_back(Pair("amount",ValueFromAmount(nValue)));
241 entry.push_back(Pair("confirmations",out.nDepth));
242 results.push_back(entry);
248 Value createrawtransaction(const Array& params, bool fHelp)
250 if (fHelp || params.size() != 2)
252 "createrawtransaction [{\"txid\":txid,\"vout\":n},...] {address:amount,...}\n"
253 "Create a transaction spending given inputs\n"
254 "(array of objects containing transaction id and output number),\n"
255 "sending to given address(es).\n"
256 "Returns hex-encoded raw transaction.\n"
257 "Note that the transaction's inputs are not signed, and\n"
258 "it is not stored in the wallet or transmitted to the network.");
260 RPCTypeCheck(params, list_of(array_type)(obj_type));
262 Array inputs = params[0].get_array();
263 Object sendTo = params[1].get_obj();
267 BOOST_FOREACH(const Value& input, inputs)
269 const Object& o = input.get_obj();
271 uint256 txid = ParseHashO(o, "txid");
273 const Value& vout_v = find_value(o, "vout");
274 if (vout_v.type() != int_type)
275 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key");
276 int nOutput = vout_v.get_int();
278 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
280 CTxIn in(COutPoint(txid, nOutput));
281 rawTx.vin.push_back(in);
284 set<CBitcoinAddress> setAddress;
285 BOOST_FOREACH(const Pair& s, sendTo)
287 CBitcoinAddress address(s.name_);
288 if (!address.IsValid())
289 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+s.name_);
291 if (setAddress.count(address))
292 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
293 setAddress.insert(address);
295 CScript scriptPubKey;
296 scriptPubKey.SetDestination(address.Get());
297 int64 nAmount = AmountFromValue(s.value_);
299 CTxOut out(nAmount, scriptPubKey);
300 rawTx.vout.push_back(out);
303 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
305 return HexStr(ss.begin(), ss.end());
308 Value decoderawtransaction(const Array& params, bool fHelp)
310 if (fHelp || params.size() != 1)
312 "decoderawtransaction <hex string>\n"
313 "Return a JSON object representing the serialized, hex-encoded transaction.");
315 vector<unsigned char> txData(ParseHexV(params[0], "argument"));
316 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
321 catch (std::exception &e) {
322 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
326 TxToJSON(tx, 0, result);
331 Value signrawtransaction(const Array& params, bool fHelp)
333 if (fHelp || params.size() < 1 || params.size() > 4)
335 "signrawtransaction <hex string> [{\"txid\":txid,\"vout\":n,\"scriptPubKey\":hex,\"redeemScript\":hex},...] [<privatekey1>,...] [sighashtype=\"ALL\"]\n"
336 "Sign inputs for raw transaction (serialized, hex-encoded).\n"
337 "Second optional argument (may be null) is an array of previous transaction outputs that\n"
338 "this transaction depends on but may not yet be in the block chain.\n"
339 "Third optional argument (may be null) is an array of base58-encoded private\n"
340 "keys that, if given, will be the only keys used to sign the transaction.\n"
341 "Fourth optional argument is a string that is one of six values; ALL, NONE, SINGLE or\n"
342 "ALL|ANYONECANPAY, NONE|ANYONECANPAY, SINGLE|ANYONECANPAY.\n"
343 "Returns json object with keys:\n"
344 " hex : raw transaction with signature(s) (hex-encoded string)\n"
345 " complete : 1 if transaction has a complete set of signature (0 if not)"
346 + HelpRequiringPassphrase());
348 RPCTypeCheck(params, list_of(str_type)(array_type)(array_type)(str_type), true);
350 vector<unsigned char> txData(ParseHexV(params[0], "argument 1"));
351 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
352 vector<CTransaction> txVariants;
353 while (!ssData.empty())
358 txVariants.push_back(tx);
360 catch (std::exception &e) {
361 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
365 if (txVariants.empty())
366 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Missing transaction");
368 // mergedTx will end up with all the signatures; it
369 // starts as a clone of the rawtx:
370 CTransaction mergedTx(txVariants[0]);
371 bool fComplete = true;
373 // Fetch previous transactions (inputs):
374 CCoinsView viewDummy;
375 CCoinsViewCache view(viewDummy);
378 CCoinsViewCache &viewChain = *pcoinsTip;
379 CCoinsViewMemPool viewMempool(viewChain, mempool);
380 view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view
382 BOOST_FOREACH(const CTxIn& txin, mergedTx.vin) {
383 const uint256& prevHash = txin.prevout.hash;
385 view.GetCoins(prevHash, coins); // this is certainly allowed to fail
388 view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long
391 bool fGivenKeys = false;
392 CBasicKeyStore tempKeystore;
393 if (params.size() > 2 && params[2].type() != null_type)
396 Array keys = params[2].get_array();
397 BOOST_FOREACH(Value k, keys)
399 CBitcoinSecret vchSecret;
400 bool fGood = vchSecret.SetString(k.get_str());
402 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
405 CSecret secret = vchSecret.GetSecret(fCompressed);
406 key.SetSecret(secret, fCompressed);
407 tempKeystore.AddKey(key);
411 EnsureWalletIsUnlocked();
413 // Add previous txouts given in the RPC call:
414 if (params.size() > 1 && params[1].type() != null_type)
416 Array prevTxs = params[1].get_array();
417 BOOST_FOREACH(Value& p, prevTxs)
419 if (p.type() != obj_type)
420 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}");
422 Object prevOut = p.get_obj();
424 RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type)("redeemScript",str_type));
426 uint256 txid = ParseHashO(prevOut, "txid");
428 int nOut = find_value(prevOut, "vout").get_int();
430 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive");
432 vector<unsigned char> pkData(ParseHexO(prevOut, "scriptPubKey"));
433 CScript scriptPubKey(pkData.begin(), pkData.end());
436 if (view.GetCoins(txid, coins)) {
437 if (coins.IsAvailable(nOut) && coins.vout[nOut].scriptPubKey != scriptPubKey) {
438 string err("Previous output scriptPubKey mismatch:\n");
439 err = err + coins.vout[nOut].scriptPubKey.ToString() + "\nvs:\n"+
440 scriptPubKey.ToString();
441 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
443 // what todo if txid is known, but the actual output isn't?
445 if ((unsigned int)nOut >= coins.vout.size())
446 coins.vout.resize(nOut+1);
447 coins.vout[nOut].scriptPubKey = scriptPubKey;
448 coins.vout[nOut].nValue = 0; // we don't know the actual output value
449 view.SetCoins(txid, coins);
451 // if redeemScript given and not using the local wallet (private keys
452 // given), add redeemScript to the tempKeystore so it can be signed:
453 Value v = find_value(prevOut, "redeemScript");
454 if (fGivenKeys && scriptPubKey.IsPayToScriptHash() && !(v == Value::null))
456 vector<unsigned char> rsData(ParseHexV(v, "redeemScript"));
457 CScript redeemScript(rsData.begin(), rsData.end());
458 tempKeystore.AddCScript(redeemScript);
463 const CKeyStore& keystore = (fGivenKeys ? tempKeystore : *pwalletMain);
465 int nHashType = SIGHASH_ALL;
466 if (params.size() > 3 && params[3].type() != null_type)
468 static map<string, int> mapSigHashValues =
469 boost::assign::map_list_of
470 (string("ALL"), int(SIGHASH_ALL))
471 (string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY))
472 (string("NONE"), int(SIGHASH_NONE))
473 (string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY))
474 (string("SINGLE"), int(SIGHASH_SINGLE))
475 (string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY))
477 string strHashType = params[3].get_str();
478 if (mapSigHashValues.count(strHashType))
479 nHashType = mapSigHashValues[strHashType];
481 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid sighash param");
484 bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
487 for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
489 CTxIn& txin = mergedTx.vin[i];
491 if (!view.GetCoins(txin.prevout.hash, coins) || !coins.IsAvailable(txin.prevout.n))
496 const CScript& prevPubKey = coins.vout[txin.prevout.n].scriptPubKey;
498 txin.scriptSig.clear();
499 // Only sign SIGHASH_SINGLE if there's a corresponding output:
500 if (!fHashSingle || (i < mergedTx.vout.size()))
501 SignSignature(keystore, prevPubKey, mergedTx, i, nHashType);
503 // ... and merge in other signatures:
504 BOOST_FOREACH(const CTransaction& txv, txVariants)
506 txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
508 if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, 0))
513 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
515 result.push_back(Pair("hex", HexStr(ssTx.begin(), ssTx.end())));
516 result.push_back(Pair("complete", fComplete));
521 Value sendrawtransaction(const Array& params, bool fHelp)
523 if (fHelp || params.size() < 1 || params.size() > 1)
525 "sendrawtransaction <hex string>\n"
526 "Submits raw transaction (serialized, hex-encoded) to local node and network.");
528 // parse hex string from parameter
529 vector<unsigned char> txData(ParseHexV(params[0], "parameter"));
530 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
533 // deserialize binary data stream
537 catch (std::exception &e) {
538 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
540 uint256 hashTx = tx.GetHash();
543 CCoinsViewCache &view = *pcoinsTip;
544 CCoins existingCoins;
546 fHave = view.GetCoins(hashTx, existingCoins);
548 // push to local node
549 if (!tx.AcceptToMemoryPool())
550 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX rejected");
554 if (existingCoins.nHeight < 1000000000)
555 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "transaction already in block chain");
556 // Not in block, but already in the memory pool; will drop
557 // through to re-relay it.
559 SyncWithWallets(hashTx, tx, NULL, true);
561 RelayMessage(CInv(MSG_TX, hashTx), tx);
563 return hashTx.GetHex();