1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2013 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"
16 using namespace boost;
17 using namespace boost::assign;
18 using namespace json_spirit;
20 void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeHex)
23 vector<CTxDestination> addresses;
26 out.push_back(Pair("asm", scriptPubKey.ToString()));
28 out.push_back(Pair("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end())));
30 if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired))
32 out.push_back(Pair("type", GetTxnOutputType(TX_NONSTANDARD)));
36 out.push_back(Pair("reqSigs", nRequired));
37 out.push_back(Pair("type", GetTxnOutputType(type)));
40 BOOST_FOREACH(const CTxDestination& addr, addresses)
41 a.push_back(CBitcoinAddress(addr).ToString());
42 out.push_back(Pair("addresses", a));
45 void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry)
47 entry.push_back(Pair("txid", tx.GetHash().GetHex()));
48 entry.push_back(Pair("version", tx.nVersion));
49 entry.push_back(Pair("locktime", (boost::int64_t)tx.nLockTime));
51 BOOST_FOREACH(const CTxIn& txin, tx.vin)
55 in.push_back(Pair("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
58 in.push_back(Pair("txid", txin.prevout.hash.GetHex()));
59 in.push_back(Pair("vout", (boost::int64_t)txin.prevout.n));
61 o.push_back(Pair("asm", txin.scriptSig.ToString()));
62 o.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
63 in.push_back(Pair("scriptSig", o));
65 in.push_back(Pair("sequence", (boost::int64_t)txin.nSequence));
68 entry.push_back(Pair("vin", vin));
70 for (unsigned int i = 0; i < tx.vout.size(); i++)
72 const CTxOut& txout = tx.vout[i];
74 out.push_back(Pair("value", ValueFromAmount(txout.nValue)));
75 out.push_back(Pair("n", (boost::int64_t)i));
77 ScriptPubKeyToJSON(txout.scriptPubKey, o, false);
78 out.push_back(Pair("scriptPubKey", o));
81 entry.push_back(Pair("vout", vout));
85 entry.push_back(Pair("blockhash", hashBlock.GetHex()));
86 map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
87 if (mi != mapBlockIndex.end() && (*mi).second)
89 CBlockIndex* pindex = (*mi).second;
90 if (chainActive.Contains(pindex))
92 entry.push_back(Pair("confirmations", 1 + chainActive.Height() - pindex->nHeight));
93 entry.push_back(Pair("time", (boost::int64_t)pindex->nTime));
94 entry.push_back(Pair("blocktime", (boost::int64_t)pindex->nTime));
97 entry.push_back(Pair("confirmations", 0));
102 Value getrawtransaction(const Array& params, bool fHelp)
104 if (fHelp || params.size() < 1 || params.size() > 2)
106 "getrawtransaction <txid> [verbose=0]\n"
107 "If verbose=0, returns a string that is\n"
108 "serialized, hex-encoded data for <txid>.\n"
109 "If verbose is non-zero, returns an Object\n"
110 "with information about <txid>.");
112 uint256 hash = ParseHashV(params[0], "parameter 1");
114 bool fVerbose = false;
115 if (params.size() > 1)
116 fVerbose = (params[1].get_int() != 0);
119 uint256 hashBlock = 0;
120 if (!GetTransaction(hash, tx, hashBlock, true))
121 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
123 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
125 string strHex = HexStr(ssTx.begin(), ssTx.end());
131 result.push_back(Pair("hex", strHex));
132 TxToJSON(tx, hashBlock, result);
136 Value listunspent(const Array& params, bool fHelp)
138 if (fHelp || params.size() > 3)
140 "listunspent [minconf=1] [maxconf=9999999] [\"address\",...]\n"
141 "Returns array of unspent transaction outputs\n"
142 "with between minconf and maxconf (inclusive) confirmations.\n"
143 "Optionally filtered to only include txouts paid to specified addresses.\n"
144 "Results are an array of Objects, each of which has:\n"
145 "{txid, vout, scriptPubKey, amount, confirmations}");
147 RPCTypeCheck(params, list_of(int_type)(int_type)(array_type));
150 if (params.size() > 0)
151 nMinDepth = params[0].get_int();
153 int nMaxDepth = 9999999;
154 if (params.size() > 1)
155 nMaxDepth = params[1].get_int();
157 set<CBitcoinAddress> setAddress;
158 if (params.size() > 2)
160 Array inputs = params[2].get_array();
161 BOOST_FOREACH(Value& input, inputs)
163 CBitcoinAddress address(input.get_str());
164 if (!address.IsValid())
165 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+input.get_str());
166 if (setAddress.count(address))
167 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str());
168 setAddress.insert(address);
173 vector<COutput> vecOutputs;
174 assert(pwalletMain != NULL);
175 pwalletMain->AvailableCoins(vecOutputs, false);
176 BOOST_FOREACH(const COutput& out, vecOutputs)
178 if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
181 if (setAddress.size())
183 CTxDestination address;
184 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
187 if (!setAddress.count(address))
191 int64 nValue = out.tx->vout[out.i].nValue;
192 const CScript& pk = out.tx->vout[out.i].scriptPubKey;
194 entry.push_back(Pair("txid", out.tx->GetHash().GetHex()));
195 entry.push_back(Pair("vout", out.i));
196 CTxDestination address;
197 if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
199 entry.push_back(Pair("address", CBitcoinAddress(address).ToString()));
200 if (pwalletMain->mapAddressBook.count(address))
201 entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name));
203 entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end())));
204 if (pk.IsPayToScriptHash())
206 CTxDestination address;
207 if (ExtractDestination(pk, address))
209 const CScriptID& hash = boost::get<const CScriptID&>(address);
210 CScript redeemScript;
211 if (pwalletMain->GetCScript(hash, redeemScript))
212 entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end())));
215 entry.push_back(Pair("amount",ValueFromAmount(nValue)));
216 entry.push_back(Pair("confirmations",out.nDepth));
217 results.push_back(entry);
223 Value createrawtransaction(const Array& params, bool fHelp)
225 if (fHelp || params.size() != 2)
227 "createrawtransaction [{\"txid\":txid,\"vout\":n},...] {address:amount,...}\n"
228 "Create a transaction spending given inputs\n"
229 "(array of objects containing transaction id and output number),\n"
230 "sending to given address(es).\n"
231 "Returns hex-encoded raw transaction.\n"
232 "Note that the transaction's inputs are not signed, and\n"
233 "it is not stored in the wallet or transmitted to the network.");
235 RPCTypeCheck(params, list_of(array_type)(obj_type));
237 Array inputs = params[0].get_array();
238 Object sendTo = params[1].get_obj();
242 BOOST_FOREACH(const Value& input, inputs)
244 const Object& o = input.get_obj();
246 uint256 txid = ParseHashO(o, "txid");
248 const Value& vout_v = find_value(o, "vout");
249 if (vout_v.type() != int_type)
250 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key");
251 int nOutput = vout_v.get_int();
253 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
255 CTxIn in(COutPoint(txid, nOutput));
256 rawTx.vin.push_back(in);
259 set<CBitcoinAddress> setAddress;
260 BOOST_FOREACH(const Pair& s, sendTo)
262 CBitcoinAddress address(s.name_);
263 if (!address.IsValid())
264 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+s.name_);
266 if (setAddress.count(address))
267 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
268 setAddress.insert(address);
270 CScript scriptPubKey;
271 scriptPubKey.SetDestination(address.Get());
272 int64 nAmount = AmountFromValue(s.value_);
274 CTxOut out(nAmount, scriptPubKey);
275 rawTx.vout.push_back(out);
278 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
280 return HexStr(ss.begin(), ss.end());
283 Value decoderawtransaction(const Array& params, bool fHelp)
285 if (fHelp || params.size() != 1)
287 "decoderawtransaction <hex string>\n"
288 "Return a JSON object representing the serialized, hex-encoded transaction.");
290 vector<unsigned char> txData(ParseHexV(params[0], "argument"));
291 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
296 catch (std::exception &e) {
297 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
301 TxToJSON(tx, 0, result);
306 Value decodescript(const Array& params, bool fHelp)
308 if (fHelp || params.size() != 1)
310 "decodescript <hex string>\n"
311 "Decode a hex-encoded script.");
313 RPCTypeCheck(params, list_of(str_type));
317 if (params[0].get_str().size() > 0){
318 vector<unsigned char> scriptData(ParseHexV(params[0], "argument"));
319 script = CScript(scriptData.begin(), scriptData.end());
321 // Empty scripts are valid
323 ScriptPubKeyToJSON(script, r, false);
325 r.push_back(Pair("p2sh", CBitcoinAddress(script.GetID()).ToString()));
329 Value signrawtransaction(const Array& params, bool fHelp)
331 if (fHelp || params.size() < 1 || params.size() > 4)
333 "signrawtransaction <hex string> [{\"txid\":txid,\"vout\":n,\"scriptPubKey\":hex,\"redeemScript\":hex},...] [<privatekey1>,...] [sighashtype=\"ALL\"]\n"
334 "Sign inputs for raw transaction (serialized, hex-encoded).\n"
335 "Second optional argument (may be null) is an array of previous transaction outputs that\n"
336 "this transaction depends on but may not yet be in the block chain.\n"
337 "Third optional argument (may be null) is an array of base58-encoded private\n"
338 "keys that, if given, will be the only keys used to sign the transaction.\n"
339 "Fourth optional argument is a string that is one of six values; ALL, NONE, SINGLE or\n"
340 "ALL|ANYONECANPAY, NONE|ANYONECANPAY, SINGLE|ANYONECANPAY.\n"
341 "Returns json object with keys:\n"
342 " hex : raw transaction with signature(s) (hex-encoded string)\n"
343 " complete : 1 if transaction has a complete set of signature (0 if not)"
344 + HelpRequiringPassphrase());
346 RPCTypeCheck(params, list_of(str_type)(array_type)(array_type)(str_type), true);
348 vector<unsigned char> txData(ParseHexV(params[0], "argument 1"));
349 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
350 vector<CTransaction> txVariants;
351 while (!ssData.empty())
356 txVariants.push_back(tx);
358 catch (std::exception &e) {
359 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
363 if (txVariants.empty())
364 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Missing transaction");
366 // mergedTx will end up with all the signatures; it
367 // starts as a clone of the rawtx:
368 CTransaction mergedTx(txVariants[0]);
369 bool fComplete = true;
371 // Fetch previous transactions (inputs):
372 CCoinsView viewDummy;
373 CCoinsViewCache view(viewDummy);
376 CCoinsViewCache &viewChain = *pcoinsTip;
377 CCoinsViewMemPool viewMempool(viewChain, mempool);
378 view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view
380 BOOST_FOREACH(const CTxIn& txin, mergedTx.vin) {
381 const uint256& prevHash = txin.prevout.hash;
383 view.GetCoins(prevHash, coins); // this is certainly allowed to fail
386 view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long
389 bool fGivenKeys = false;
390 CBasicKeyStore tempKeystore;
391 if (params.size() > 2 && params[2].type() != null_type)
394 Array keys = params[2].get_array();
395 BOOST_FOREACH(Value k, keys)
397 CBitcoinSecret vchSecret;
398 bool fGood = vchSecret.SetString(k.get_str());
400 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
401 CKey key = vchSecret.GetKey();
402 tempKeystore.AddKey(key);
406 EnsureWalletIsUnlocked();
408 // Add previous txouts given in the RPC call:
409 if (params.size() > 1 && params[1].type() != null_type)
411 Array prevTxs = params[1].get_array();
412 BOOST_FOREACH(Value& p, prevTxs)
414 if (p.type() != obj_type)
415 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}");
417 Object prevOut = p.get_obj();
419 RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type));
421 uint256 txid = ParseHashO(prevOut, "txid");
423 int nOut = find_value(prevOut, "vout").get_int();
425 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive");
427 vector<unsigned char> pkData(ParseHexO(prevOut, "scriptPubKey"));
428 CScript scriptPubKey(pkData.begin(), pkData.end());
431 if (view.GetCoins(txid, coins)) {
432 if (coins.IsAvailable(nOut) && coins.vout[nOut].scriptPubKey != scriptPubKey) {
433 string err("Previous output scriptPubKey mismatch:\n");
434 err = err + coins.vout[nOut].scriptPubKey.ToString() + "\nvs:\n"+
435 scriptPubKey.ToString();
436 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
438 // what todo if txid is known, but the actual output isn't?
440 if ((unsigned int)nOut >= coins.vout.size())
441 coins.vout.resize(nOut+1);
442 coins.vout[nOut].scriptPubKey = scriptPubKey;
443 coins.vout[nOut].nValue = 0; // we don't know the actual output value
444 view.SetCoins(txid, coins);
446 // if redeemScript given and not using the local wallet (private keys
447 // given), add redeemScript to the tempKeystore so it can be signed:
448 if (fGivenKeys && scriptPubKey.IsPayToScriptHash())
450 RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type)("redeemScript",str_type));
451 Value v = find_value(prevOut, "redeemScript");
452 if (!(v == Value::null))
454 vector<unsigned char> rsData(ParseHexV(v, "redeemScript"));
455 CScript redeemScript(rsData.begin(), rsData.end());
456 tempKeystore.AddCScript(redeemScript);
462 const CKeyStore& keystore = ((fGivenKeys || !pwalletMain) ? tempKeystore : *pwalletMain);
464 int nHashType = SIGHASH_ALL;
465 if (params.size() > 3 && params[3].type() != null_type)
467 static map<string, int> mapSigHashValues =
468 boost::assign::map_list_of
469 (string("ALL"), int(SIGHASH_ALL))
470 (string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY))
471 (string("NONE"), int(SIGHASH_NONE))
472 (string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY))
473 (string("SINGLE"), int(SIGHASH_SINGLE))
474 (string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY))
476 string strHashType = params[3].get_str();
477 if (mapSigHashValues.count(strHashType))
478 nHashType = mapSigHashValues[strHashType];
480 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid sighash param");
483 bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
486 for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
488 CTxIn& txin = mergedTx.vin[i];
490 if (!view.GetCoins(txin.prevout.hash, coins) || !coins.IsAvailable(txin.prevout.n))
495 const CScript& prevPubKey = coins.vout[txin.prevout.n].scriptPubKey;
497 txin.scriptSig.clear();
498 // Only sign SIGHASH_SINGLE if there's a corresponding output:
499 if (!fHashSingle || (i < mergedTx.vout.size()))
500 SignSignature(keystore, prevPubKey, mergedTx, i, nHashType);
502 // ... and merge in other signatures:
503 BOOST_FOREACH(const CTransaction& txv, txVariants)
505 txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
507 if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, 0))
512 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
514 result.push_back(Pair("hex", HexStr(ssTx.begin(), ssTx.end())));
515 result.push_back(Pair("complete", fComplete));
520 Value sendrawtransaction(const Array& params, bool fHelp)
522 if (fHelp || params.size() < 1 || params.size() > 2)
524 "sendrawtransaction <hex string> [allowhighfees=false]\n"
525 "Submits raw transaction (serialized, hex-encoded) to local node and network.");
527 // parse hex string from parameter
528 vector<unsigned char> txData(ParseHexV(params[0], "parameter"));
529 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
532 bool fOverrideFees = false;
533 if (params.size() > 1)
534 fOverrideFees = params[1].get_bool();
536 // deserialize binary data stream
540 catch (std::exception &e) {
541 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
543 uint256 hashTx = tx.GetHash();
546 CCoinsViewCache &view = *pcoinsTip;
547 CCoins existingCoins;
549 fHave = view.GetCoins(hashTx, existingCoins);
551 // push to local node
552 CValidationState state;
553 if (!mempool.accept(state, tx, false, NULL, !fOverrideFees))
554 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX rejected"); // TODO: report validation state
558 if (existingCoins.nHeight < 1000000000)
559 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "transaction already in block chain");
560 // Not in block, but already in the memory pool; will drop
561 // through to re-relay it.
563 SyncWithWallets(hashTx, tx, NULL);
565 RelayTransaction(tx, hashTx);
567 return hashTx.GetHex();