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;
21 void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeHex)
24 vector<CTxDestination> addresses;
27 out.push_back(Pair("asm", scriptPubKey.ToString()));
30 out.push_back(Pair("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end())));
32 if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired))
34 out.push_back(Pair("type", GetTxnOutputType(TX_NONSTANDARD)));
38 out.push_back(Pair("reqSigs", nRequired));
39 out.push_back(Pair("type", GetTxnOutputType(type)));
42 BOOST_FOREACH(const CTxDestination& addr, addresses)
43 a.push_back(CBitcoinAddress(addr).ToString());
44 out.push_back(Pair("addresses", a));
47 void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry)
49 entry.push_back(Pair("txid", tx.GetHash().GetHex()));
50 entry.push_back(Pair("version", tx.nVersion));
51 entry.push_back(Pair("time", (boost::int64_t)tx.nTime));
52 entry.push_back(Pair("locktime", (boost::int64_t)tx.nLockTime));
54 BOOST_FOREACH(const CTxIn& txin, tx.vin)
58 in.push_back(Pair("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
61 in.push_back(Pair("txid", txin.prevout.hash.GetHex()));
62 in.push_back(Pair("vout", (boost::int64_t)txin.prevout.n));
64 o.push_back(Pair("asm", txin.scriptSig.ToString()));
65 o.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
66 in.push_back(Pair("scriptSig", o));
68 in.push_back(Pair("sequence", (boost::int64_t)txin.nSequence));
71 entry.push_back(Pair("vin", vin));
73 for (unsigned int i = 0; i < tx.vout.size(); i++)
75 const CTxOut& txout = tx.vout[i];
77 out.push_back(Pair("value", ValueFromAmount(txout.nValue)));
78 out.push_back(Pair("n", (boost::int64_t)i));
80 ScriptPubKeyToJSON(txout.scriptPubKey, o, false);
81 out.push_back(Pair("scriptPubKey", o));
84 entry.push_back(Pair("vout", vout));
88 entry.push_back(Pair("blockhash", hashBlock.GetHex()));
89 map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
90 if (mi != mapBlockIndex.end() && (*mi).second)
92 CBlockIndex* pindex = (*mi).second;
93 if (pindex->IsInMainChain())
95 entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight));
96 entry.push_back(Pair("time", (boost::int64_t)pindex->nTime));
97 entry.push_back(Pair("blocktime", (boost::int64_t)pindex->nTime));
100 entry.push_back(Pair("confirmations", 0));
105 Value getrawtransaction(const Array& params, bool fHelp)
107 if (fHelp || params.size() < 1 || params.size() > 2)
109 "getrawtransaction <txid> [verbose=0]\n"
110 "If verbose=0, returns a string that is\n"
111 "serialized, hex-encoded data for <txid>.\n"
112 "If verbose is non-zero, returns an Object\n"
113 "with information about <txid>.");
116 hash.SetHex(params[0].get_str());
118 bool fVerbose = false;
119 if (params.size() > 1)
120 fVerbose = (params[1].get_int() != 0);
123 uint256 hashBlock = 0;
124 if (!GetTransaction(hash, tx, hashBlock))
125 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
127 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
129 string strHex = HexStr(ssTx.begin(), ssTx.end());
135 result.push_back(Pair("hex", strHex));
136 TxToJSON(tx, hashBlock, result);
140 Value listunspent(const Array& params, bool fHelp)
142 if (fHelp || params.size() > 3)
144 "listunspent [minconf=1] [maxconf=9999999] [\"address\",...]\n"
145 "Returns array of unspent transaction outputs\n"
146 "with between minconf and maxconf (inclusive) confirmations.\n"
147 "Optionally filtered to only include txouts paid to specified addresses.\n"
148 "Results are an array of Objects, each of which has:\n"
149 "{txid, vout, scriptPubKey, amount, confirmations}");
151 RPCTypeCheck(params, list_of(int_type)(int_type)(array_type));
154 if (params.size() > 0)
155 nMinDepth = params[0].get_int();
157 int nMaxDepth = 9999999;
158 if (params.size() > 1)
159 nMaxDepth = params[1].get_int();
161 set<CBitcoinAddress> setAddress;
162 if (params.size() > 2)
164 Array inputs = params[2].get_array();
165 BOOST_FOREACH(Value& input, inputs)
167 CBitcoinAddress address(input.get_str());
168 if (!address.IsValid())
169 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid NovaCoin address: ")+input.get_str());
170 if (setAddress.count(address))
171 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str());
172 setAddress.insert(address);
177 vector<COutput> vecOutputs;
178 pwalletMain->AvailableCoins(vecOutputs, false);
179 BOOST_FOREACH(const COutput& out, vecOutputs)
181 if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
184 if(setAddress.size())
186 CTxDestination address;
187 if(!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
190 if (!setAddress.count(address))
194 int64 nValue = out.tx->vout[out.i].nValue;
195 const CScript& pk = out.tx->vout[out.i].scriptPubKey;
197 entry.push_back(Pair("txid", out.tx->GetHash().GetHex()));
198 entry.push_back(Pair("vout", out.i));
199 CTxDestination address;
200 if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
202 entry.push_back(Pair("address", CBitcoinAddress(address).ToString()));
203 if (pwalletMain->mapAddressBook.count(address))
204 entry.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
206 entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end())));
207 if (pk.IsPayToScriptHash())
209 CTxDestination address;
210 if (ExtractDestination(pk, address))
212 const CScriptID& hash = boost::get<const CScriptID&>(address);
213 CScript redeemScript;
214 if (pwalletMain->GetCScript(hash, redeemScript))
215 entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end())));
218 entry.push_back(Pair("amount",ValueFromAmount(nValue)));
219 entry.push_back(Pair("confirmations",out.nDepth));
220 results.push_back(entry);
226 Value createrawtransaction(const Array& params, bool fHelp)
228 if (fHelp || params.size() != 2)
230 "createrawtransaction [{\"txid\":txid,\"vout\":n},...] {address:amount,...}\n"
231 "Create a transaction spending given inputs\n"
232 "(array of objects containing transaction id and output number),\n"
233 "sending to given address(es).\n"
234 "Returns hex-encoded raw transaction.\n"
235 "Note that the transaction's inputs are not signed, and\n"
236 "it is not stored in the wallet or transmitted to the network.");
238 RPCTypeCheck(params, list_of(array_type)(obj_type));
240 Array inputs = params[0].get_array();
241 Object sendTo = params[1].get_obj();
245 BOOST_FOREACH(Value& input, inputs)
247 const Object& o = input.get_obj();
249 const Value& txid_v = find_value(o, "txid");
250 if (txid_v.type() != str_type)
251 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing txid key");
252 string txid = txid_v.get_str();
254 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
256 const Value& vout_v = find_value(o, "vout");
257 if (vout_v.type() != int_type)
258 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key");
259 int nOutput = vout_v.get_int();
261 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
263 CTxIn in(COutPoint(uint256(txid), nOutput));
264 rawTx.vin.push_back(in);
267 set<CBitcoinAddress> setAddress;
268 BOOST_FOREACH(const Pair& s, sendTo)
270 CBitcoinAddress address(s.name_);
271 if (!address.IsValid())
272 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid NovaCoin address: ")+s.name_);
274 if (setAddress.count(address))
275 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
276 setAddress.insert(address);
278 CScript scriptPubKey;
279 scriptPubKey.SetDestination(address.Get());
280 int64 nAmount = AmountFromValue(s.value_);
282 CTxOut out(nAmount, scriptPubKey);
283 rawTx.vout.push_back(out);
286 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
288 return HexStr(ss.begin(), ss.end());
291 Value decoderawtransaction(const Array& params, bool fHelp)
293 if (fHelp || params.size() != 1)
295 "decoderawtransaction <hex string>\n"
296 "Return a JSON object representing the serialized, hex-encoded transaction.");
298 RPCTypeCheck(params, list_of(str_type));
300 vector<unsigned char> txData(ParseHex(params[0].get_str()));
301 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
306 catch (std::exception &e) {
307 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
311 TxToJSON(tx, 0, result);
316 Value decodescript(const Array& params, bool fHelp)
318 if (fHelp || params.size() != 1)
320 "decodescript <hex string>\n"
321 "Decode a hex-encoded script.");
323 RPCTypeCheck(params, list_of(str_type));
327 if (params[0].get_str().size() > 0){
328 vector<unsigned char> scriptData(ParseHexV(params[0], "argument"));
329 script = CScript(scriptData.begin(), scriptData.end());
331 // Empty scripts are valid
333 ScriptPubKeyToJSON(script, r, false);
335 r.push_back(Pair("p2sh", CBitcoinAddress(script.GetID()).ToString()));
339 Value signrawtransaction(const Array& params, bool fHelp)
341 if (fHelp || params.size() < 1 || params.size() > 4)
343 "signrawtransaction <hex string> [{\"txid\":txid,\"vout\":n,\"scriptPubKey\":hex,\"redeemScript\":hex},...] [<privatekey1>,...] [sighashtype=\"ALL\"]\n"
344 "Sign inputs for raw transaction (serialized, hex-encoded).\n"
345 "Second optional argument (may be null) is an array of previous transaction outputs that\n"
346 "this transaction depends on but may not yet be in the blockchain.\n"
347 "Third optional argument (may be null) is an array of base58-encoded private\n"
348 "keys that, if given, will be the only keys used to sign the transaction.\n"
349 "Fourth optional argument is a string that is one of six values; ALL, NONE, SINGLE or\n"
350 "ALL|ANYONECANPAY, NONE|ANYONECANPAY, SINGLE|ANYONECANPAY.\n"
351 "Returns json object with keys:\n"
352 " hex : raw transaction with signature(s) (hex-encoded string)\n"
353 " complete : 1 if transaction has a complete set of signature (0 if not)"
354 + HelpRequiringPassphrase());
356 RPCTypeCheck(params, list_of(str_type)(array_type)(array_type)(str_type), true);
358 vector<unsigned char> txData(ParseHex(params[0].get_str()));
359 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
360 vector<CTransaction> txVariants;
361 while (!ssData.empty())
366 txVariants.push_back(tx);
368 catch (std::exception &e) {
369 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
373 if (txVariants.empty())
374 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Missing transaction");
376 // mergedTx will end up with all the signatures; it
377 // starts as a clone of the rawtx:
378 CTransaction mergedTx(txVariants[0]);
379 bool fComplete = true;
381 // Fetch previous transactions (inputs):
382 map<COutPoint, CScript> mapPrevOut;
383 for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
388 map<uint256, CTxIndex> unused;
391 // FetchInputs aborts on failure, so we go one at a time.
392 tempTx.vin.push_back(mergedTx.vin[i]);
393 tempTx.FetchInputs(txdb, unused, false, false, mapPrevTx, fInvalid);
395 // Copy results into mapPrevOut:
396 BOOST_FOREACH(const CTxIn& txin, tempTx.vin)
398 const uint256& prevHash = txin.prevout.hash;
399 if (mapPrevTx.count(prevHash) && mapPrevTx[prevHash].second.vout.size()>txin.prevout.n)
400 mapPrevOut[txin.prevout] = mapPrevTx[prevHash].second.vout[txin.prevout.n].scriptPubKey;
404 bool fGivenKeys = false;
405 CBasicKeyStore tempKeystore;
406 if (params.size() > 2 && params[2].type() != null_type)
409 Array keys = params[2].get_array();
410 BOOST_FOREACH(Value k, keys)
412 CBitcoinSecret vchSecret;
413 bool fGood = vchSecret.SetString(k.get_str());
415 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
418 CSecret secret = vchSecret.GetSecret(fCompressed);
419 key.SetSecret(secret, fCompressed);
420 tempKeystore.AddKey(key);
424 EnsureWalletIsUnlocked();
426 // Add previous txouts given in the RPC call:
427 if (params.size() > 1 && params[1].type() != null_type)
429 Array prevTxs = params[1].get_array();
430 BOOST_FOREACH(Value& p, prevTxs)
432 if (p.type() != obj_type)
433 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}");
435 Object prevOut = p.get_obj();
437 RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type));
439 string txidHex = find_value(prevOut, "txid").get_str();
441 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "txid must be hexadecimal");
443 txid.SetHex(txidHex);
445 int nOut = find_value(prevOut, "vout").get_int();
447 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive");
449 string pkHex = find_value(prevOut, "scriptPubKey").get_str();
451 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "scriptPubKey must be hexadecimal");
452 vector<unsigned char> pkData(ParseHex(pkHex));
453 CScript scriptPubKey(pkData.begin(), pkData.end());
455 COutPoint outpoint(txid, nOut);
456 if (mapPrevOut.count(outpoint))
458 // Complain if scriptPubKey doesn't match
459 if (mapPrevOut[outpoint] != scriptPubKey)
461 string err("Previous output scriptPubKey mismatch:\n");
462 err = err + mapPrevOut[outpoint].ToString() + "\nvs:\n"+
463 scriptPubKey.ToString();
464 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
468 mapPrevOut[outpoint] = scriptPubKey;
470 // if redeemScript given and not using the local wallet (private keys
471 // given), add redeemScript to the tempKeystore so it can be signed:
472 Value v = find_value(prevOut, "redeemScript");
473 if (fGivenKeys && scriptPubKey.IsPayToScriptHash())
475 RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type)("redeemScript",str_type));
476 Value v = find_value(prevOut, "redeemScript");
477 if (!(v == Value::null))
479 vector<unsigned char> rsData(ParseHexV(v, "redeemScript"));
480 CScript redeemScript(rsData.begin(), rsData.end());
481 tempKeystore.AddCScript(redeemScript);
487 const CKeyStore& keystore = (fGivenKeys ? tempKeystore : *pwalletMain);
489 int nHashType = SIGHASH_ALL;
490 if (params.size() > 3 && params[3].type() != null_type)
492 static map<string, int> mapSigHashValues =
493 boost::assign::map_list_of
494 (string("ALL"), int(SIGHASH_ALL))
495 (string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY))
496 (string("NONE"), int(SIGHASH_NONE))
497 (string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY))
498 (string("SINGLE"), int(SIGHASH_SINGLE))
499 (string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY))
501 string strHashType = params[3].get_str();
502 if (mapSigHashValues.count(strHashType))
503 nHashType = mapSigHashValues[strHashType];
505 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid sighash param");
508 bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
511 for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
513 CTxIn& txin = mergedTx.vin[i];
514 if (mapPrevOut.count(txin.prevout) == 0)
519 const CScript& prevPubKey = mapPrevOut[txin.prevout];
521 txin.scriptSig.clear();
522 // Only sign SIGHASH_SINGLE if there's a corresponding output:
523 if (!fHashSingle || (i < mergedTx.vout.size()))
524 SignSignature(keystore, prevPubKey, mergedTx, i, nHashType);
526 // ... and merge in other signatures:
527 BOOST_FOREACH(const CTransaction& txv, txVariants)
529 txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
531 if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, STRICT_FLAGS, 0))
536 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
538 result.push_back(Pair("hex", HexStr(ssTx.begin(), ssTx.end())));
539 result.push_back(Pair("complete", fComplete));
544 Value sendrawtransaction(const Array& params, bool fHelp)
546 if (fHelp || params.size() < 1 || params.size() > 1)
548 "sendrawtransaction <hex string>\n"
549 "Submits raw transaction (serialized, hex-encoded) to local node and network.");
551 RPCTypeCheck(params, list_of(str_type));
553 // parse hex string from parameter
554 vector<unsigned char> txData(ParseHex(params[0].get_str()));
555 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
558 // deserialize binary data stream
562 catch (std::exception &e) {
563 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
565 uint256 hashTx = tx.GetHash();
567 // See if the transaction is already in a block
568 // or in the memory pool:
569 CTransaction existingTx;
570 uint256 hashBlock = 0;
571 if (GetTransaction(hashTx, existingTx, hashBlock))
574 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("transaction already in block ")+hashBlock.GetHex());
575 // Not in block, but already in the memory pool; will drop
576 // through to re-relay it.
580 // push to local node
582 if (!tx.AcceptToMemoryPool(txdb))
583 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX rejected");
585 SyncWithWallets(tx, NULL, true);
587 RelayTransaction(tx, hashTx);
589 return hashTx.GetHex();