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 if (type != TX_NULL_DATA)
40 out.push_back(Pair("reqSigs", nRequired));
41 out.push_back(Pair("type", GetTxnOutputType(type)));
43 if (type == TX_PUBKEY_DROP)
45 vector<valtype> vSolutions;
46 if (!Solver(scriptPubKey, type, vSolutions))
48 out.push_back(Pair("keyVariant", HexStr(vSolutions[0])));
49 out.push_back(Pair("R", HexStr(vSolutions[1])));
54 BOOST_FOREACH(const CTxDestination& addr, addresses)
55 a.push_back(CBitcoinAddress(addr).ToString());
56 out.push_back(Pair("addresses", a));
60 out.push_back(Pair("type", GetTxnOutputType(type)));
64 void TxToJSON(const CTransaction& tx, const uint256& hashBlock, Object& entry)
66 entry.push_back(Pair("txid", tx.GetHash().GetHex()));
67 entry.push_back(Pair("version", tx.nVersion));
68 entry.push_back(Pair("time", (int64_t)tx.nTime));
69 entry.push_back(Pair("locktime", (int64_t)tx.nLockTime));
71 BOOST_FOREACH(const CTxIn& txin, tx.vin)
75 in.push_back(Pair("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
78 in.push_back(Pair("txid", txin.prevout.hash.GetHex()));
79 in.push_back(Pair("vout", (int64_t)txin.prevout.n));
81 o.push_back(Pair("asm", txin.scriptSig.ToString()));
82 o.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
83 in.push_back(Pair("scriptSig", o));
85 in.push_back(Pair("sequence", (int64_t)txin.nSequence));
88 entry.push_back(Pair("vin", vin));
90 for (unsigned int i = 0; i < tx.vout.size(); i++)
92 const CTxOut& txout = tx.vout[i];
94 out.push_back(Pair("value", ValueFromAmount(txout.nValue)));
95 out.push_back(Pair("n", (int64_t)i));
97 ScriptPubKeyToJSON(txout.scriptPubKey, o, true);
98 out.push_back(Pair("scriptPubKey", o));
101 entry.push_back(Pair("vout", vout));
105 entry.push_back(Pair("blockhash", hashBlock.GetHex()));
106 map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
107 if (mi != mapBlockIndex.end() && (*mi).second)
109 CBlockIndex* pindex = (*mi).second;
110 if (pindex->IsInMainChain())
112 entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight));
113 entry.push_back(Pair("time", (int64_t)pindex->nTime));
114 entry.push_back(Pair("blocktime", (int64_t)pindex->nTime));
117 entry.push_back(Pair("confirmations", 0));
122 Value getrawtransaction(const Array& params, bool fHelp)
124 if (fHelp || params.size() < 1 || params.size() > 2)
126 "getrawtransaction <txid> [verbose=0]\n"
127 "If verbose=0, returns a string that is\n"
128 "serialized, hex-encoded data for <txid>.\n"
129 "If verbose is non-zero, returns an Object\n"
130 "with information about <txid>.");
133 hash.SetHex(params[0].get_str());
135 bool fVerbose = false;
136 if (params.size() > 1)
137 fVerbose = (params[1].get_int() != 0);
140 uint256 hashBlock = 0;
141 if (!GetTransaction(hash, tx, hashBlock))
142 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
144 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
146 string strHex = HexStr(ssTx.begin(), ssTx.end());
152 result.push_back(Pair("hex", strHex));
153 TxToJSON(tx, hashBlock, result);
157 Value listunspent(const Array& params, bool fHelp)
159 if (fHelp || params.size() > 3)
161 "listunspent [minconf=1] [maxconf=9999999] [\"address\",...]\n"
162 "Returns array of unspent transaction outputs\n"
163 "with between minconf and maxconf (inclusive) confirmations.\n"
164 "Optionally filtered to only include txouts paid to specified addresses.\n"
165 "Results are an array of Objects, each of which has:\n"
166 "{txid, vout, scriptPubKey, amount, confirmations}");
168 RPCTypeCheck(params, list_of(int_type)(int_type)(array_type));
171 if (params.size() > 0)
172 nMinDepth = params[0].get_int();
174 int nMaxDepth = 9999999;
175 if (params.size() > 1)
176 nMaxDepth = params[1].get_int();
178 set<CBitcoinAddress> setAddress;
179 if (params.size() > 2)
181 Array inputs = params[2].get_array();
182 BOOST_FOREACH(Value& input, inputs)
184 CBitcoinAddress address(input.get_str());
185 if (!address.IsValid())
186 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid NovaCoin address: ")+input.get_str());
187 if (setAddress.count(address))
188 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str());
189 setAddress.insert(address);
194 vector<COutput> vecOutputs;
195 pwalletMain->AvailableCoins(vecOutputs, false);
196 BOOST_FOREACH(const COutput& out, vecOutputs)
198 if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
201 if(setAddress.size())
203 CTxDestination address;
204 if(!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
207 if (!setAddress.count(address))
211 int64_t nValue = out.tx->vout[out.i].nValue;
212 const CScript& pk = out.tx->vout[out.i].scriptPubKey;
214 entry.push_back(Pair("txid", out.tx->GetHash().GetHex()));
215 entry.push_back(Pair("vout", out.i));
216 CTxDestination address;
217 if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
219 entry.push_back(Pair("address", CBitcoinAddress(address).ToString()));
220 if (pwalletMain->mapAddressBook.count(address))
221 entry.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
223 entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end())));
224 if (pk.IsPayToScriptHash())
226 CTxDestination address;
227 if (ExtractDestination(pk, address))
229 const CScriptID& hash = boost::get<CScriptID>(address);
230 CScript redeemScript;
231 if (pwalletMain->GetCScript(hash, redeemScript))
232 entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end())));
235 entry.push_back(Pair("amount",ValueFromAmount(nValue)));
236 entry.push_back(Pair("confirmations",out.nDepth));
237 entry.push_back(Pair("spendable", out.fSpendable));
238 results.push_back(entry);
244 Value createrawtransaction(const Array& params, bool fHelp)
246 if (fHelp || params.size() > 3 || params.size() < 2)
248 "createrawtransaction <'[{\"txid\":txid,\"vout\":n},...]'> <'{address:amount,...}'> [hex data]\n"
249 "Create a transaction spending given inputs\n"
250 "(array of objects containing transaction id and output number),\n"
251 "sending to given address(es),\n"
252 "optional data to add into data-carrying output.\n"
253 "Returns hex-encoded raw transaction.\n"
254 "Note that the transaction's inputs are not signed, and\n"
255 "it is not stored in the wallet or transmitted to the network.");
257 RPCTypeCheck(params, list_of(array_type)(obj_type));
259 Array inputs = params[0].get_array();
260 Object sendTo = params[1].get_obj();
264 BOOST_FOREACH(Value& input, inputs)
266 const Object& o = input.get_obj();
268 const Value& txid_v = find_value(o, "txid");
269 if (txid_v.type() != str_type)
270 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing txid key");
271 string txid = txid_v.get_str();
273 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
275 const Value& vout_v = find_value(o, "vout");
276 if (vout_v.type() != int_type)
277 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key");
278 int nOutput = vout_v.get_int();
280 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
282 CTxIn in(COutPoint(uint256(txid), nOutput));
283 rawTx.vin.push_back(in);
286 set<CBitcoinAddress> setAddress;
287 BOOST_FOREACH(const Pair& s, sendTo)
289 CBitcoinAddress address(s.name_);
290 if (!address.IsValid())
291 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid NovaCoin address: ")+s.name_);
293 if (setAddress.count(address))
294 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
295 setAddress.insert(address);
297 CScript scriptPubKey;
298 scriptPubKey.SetDestination(address.Get());
299 int64_t nAmount = AmountFromValue(s.value_);
301 CTxOut out(nAmount, scriptPubKey);
302 rawTx.vout.push_back(out);
305 if (params.size() == 3)
307 // Data carrying output
308 CScript scriptPubKey;
309 scriptPubKey << OP_RETURN << ParseHex(params[2].get_str());
310 CTxOut out(0, scriptPubKey);
311 rawTx.vout.push_back(out);
314 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
316 return HexStr(ss.begin(), ss.end());
319 Value decoderawtransaction(const Array& params, bool fHelp)
321 if (fHelp || params.size() != 1)
323 "decoderawtransaction <hex string>\n"
324 "Return a JSON object representing the serialized, hex-encoded transaction.");
326 RPCTypeCheck(params, list_of(str_type));
328 vector<unsigned char> txData(ParseHex(params[0].get_str()));
329 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
334 catch (const std::exception&) {
335 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
339 TxToJSON(tx, 0, result);
344 Value decodescript(const Array& params, bool fHelp)
346 if (fHelp || params.size() != 1)
348 "decodescript <hex string>\n"
349 "Decode a hex-encoded script.");
351 RPCTypeCheck(params, list_of(str_type));
355 if (params[0].get_str().size() > 0){
356 vector<unsigned char> scriptData(ParseHexV(params[0], "argument"));
357 script = CScript(scriptData.begin(), scriptData.end());
359 // Empty scripts are valid
361 ScriptPubKeyToJSON(script, r, false);
363 r.push_back(Pair("p2sh", CBitcoinAddress(script.GetID()).ToString()));
367 Value signrawtransaction(const Array& params, bool fHelp)
369 if (fHelp || params.size() < 1 || params.size() > 4)
371 "signrawtransaction <hex string> '[{\"txid\":txid,\"vout\":n,\"scriptPubKey\":hex,\"redeemScript\":hex},...]' '[<privatekey1>,...]' [sighashtype=\"ALL\"]\n"
372 "Sign inputs for raw transaction (serialized, hex-encoded).\n"
373 "Second optional argument (may be null) is an array of previous transaction outputs that\n"
374 "this transaction depends on but may not yet be in the blockchain.\n"
375 "Third optional argument (may be null) is an array of base58-encoded private\n"
376 "keys that, if given, will be the only keys used to sign the transaction.\n"
377 "Fourth optional argument is a string that is one of six values; ALL, NONE, SINGLE or\n"
378 "ALL|ANYONECANPAY, NONE|ANYONECANPAY, SINGLE|ANYONECANPAY.\n"
379 "Returns json object with keys:\n"
380 " hex : raw transaction with signature(s) (hex-encoded string)\n"
381 " complete : 1 if transaction has a complete set of signature (0 if not)"
382 + HelpRequiringPassphrase());
384 RPCTypeCheck(params, list_of(str_type)(array_type)(array_type)(str_type), true);
386 vector<unsigned char> txData(ParseHex(params[0].get_str()));
387 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
388 vector<CTransaction> txVariants;
389 while (!ssData.empty())
394 txVariants.push_back(tx);
396 catch (const std::exception&) {
397 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
401 if (txVariants.empty())
402 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Missing transaction");
404 // mergedTx will end up with all the signatures; it
405 // starts as a clone of the rawtx:
406 CTransaction mergedTx(txVariants[0]);
407 bool fComplete = true;
409 // Fetch previous transactions (inputs):
410 map<COutPoint, CScript> mapPrevOut;
411 for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
416 map<uint256, CTxIndex> unused;
419 // FetchInputs aborts on failure, so we go one at a time.
420 tempTx.vin.push_back(mergedTx.vin[i]);
421 tempTx.FetchInputs(txdb, unused, false, false, mapPrevTx, fInvalid);
423 // Copy results into mapPrevOut:
424 BOOST_FOREACH(const CTxIn& txin, tempTx.vin)
426 const uint256& prevHash = txin.prevout.hash;
427 if (mapPrevTx.count(prevHash) && mapPrevTx[prevHash].second.vout.size()>txin.prevout.n)
428 mapPrevOut[txin.prevout] = mapPrevTx[prevHash].second.vout[txin.prevout.n].scriptPubKey;
432 bool fGivenKeys = false;
433 CBasicKeyStore tempKeystore;
434 if (params.size() > 2 && params[2].type() != null_type)
437 Array keys = params[2].get_array();
438 BOOST_FOREACH(Value k, keys)
440 CBitcoinSecret vchSecret;
441 bool fGood = vchSecret.SetString(k.get_str());
443 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
446 CSecret secret = vchSecret.GetSecret(fCompressed);
447 key.SetSecret(secret, fCompressed);
448 tempKeystore.AddKey(key);
452 EnsureWalletIsUnlocked();
454 // Add previous txouts given in the RPC call:
455 if (params.size() > 1 && params[1].type() != null_type)
457 Array prevTxs = params[1].get_array();
458 BOOST_FOREACH(Value& p, prevTxs)
460 if (p.type() != obj_type)
461 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}");
463 Object prevOut = p.get_obj();
465 RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type));
467 string txidHex = find_value(prevOut, "txid").get_str();
469 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "txid must be hexadecimal");
471 txid.SetHex(txidHex);
473 int nOut = find_value(prevOut, "vout").get_int();
475 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive");
477 string pkHex = find_value(prevOut, "scriptPubKey").get_str();
479 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "scriptPubKey must be hexadecimal");
480 vector<unsigned char> pkData(ParseHex(pkHex));
481 CScript scriptPubKey(pkData.begin(), pkData.end());
483 COutPoint outpoint(txid, nOut);
484 if (mapPrevOut.count(outpoint))
486 // Complain if scriptPubKey doesn't match
487 if (mapPrevOut[outpoint] != scriptPubKey)
489 string err("Previous output scriptPubKey mismatch:\n");
490 err = err + mapPrevOut[outpoint].ToString() + "\nvs:\n"+
491 scriptPubKey.ToString();
492 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
496 mapPrevOut[outpoint] = scriptPubKey;
498 // if redeemScript given and not using the local wallet (private keys
499 // given), add redeemScript to the tempKeystore so it can be signed:
500 Value v = find_value(prevOut, "redeemScript");
501 if (fGivenKeys && scriptPubKey.IsPayToScriptHash())
503 RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type)("redeemScript",str_type));
504 Value v = find_value(prevOut, "redeemScript");
505 if (!(v == Value::null))
507 vector<unsigned char> rsData(ParseHexV(v, "redeemScript"));
508 CScript redeemScript(rsData.begin(), rsData.end());
509 tempKeystore.AddCScript(redeemScript);
515 const CKeyStore& keystore = (fGivenKeys ? tempKeystore : *pwalletMain);
517 int nHashType = SIGHASH_ALL;
518 if (params.size() > 3 && params[3].type() != null_type)
520 static map<string, int> mapSigHashValues =
521 boost::assign::map_list_of
522 (string("ALL"), int(SIGHASH_ALL))
523 (string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY))
524 (string("NONE"), int(SIGHASH_NONE))
525 (string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY))
526 (string("SINGLE"), int(SIGHASH_SINGLE))
527 (string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY))
529 string strHashType = params[3].get_str();
530 if (mapSigHashValues.count(strHashType))
531 nHashType = mapSigHashValues[strHashType];
533 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid sighash param");
536 bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
539 for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
541 CTxIn& txin = mergedTx.vin[i];
542 if (mapPrevOut.count(txin.prevout) == 0)
547 const CScript& prevPubKey = mapPrevOut[txin.prevout];
549 txin.scriptSig.clear();
550 // Only sign SIGHASH_SINGLE if there's a corresponding output:
551 if (!fHashSingle || (i < mergedTx.vout.size()))
552 SignSignature(keystore, prevPubKey, mergedTx, i, nHashType);
554 // ... and merge in other signatures:
555 BOOST_FOREACH(const CTransaction& txv, txVariants)
557 txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
559 if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, STRICT_FLAGS, 0))
564 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
566 result.push_back(Pair("hex", HexStr(ssTx.begin(), ssTx.end())));
567 result.push_back(Pair("complete", fComplete));
572 Value sendrawtransaction(const Array& params, bool fHelp)
574 if (fHelp || params.size() < 1 || params.size() > 1)
576 "sendrawtransaction <hex string>\n"
577 "Submits raw transaction (serialized, hex-encoded) to local node and network.");
579 RPCTypeCheck(params, list_of(str_type));
581 // parse hex string from parameter
582 vector<unsigned char> txData(ParseHex(params[0].get_str()));
583 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
586 // deserialize binary data stream
590 catch (const std::exception&) {
591 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
593 uint256 hashTx = tx.GetHash();
595 // See if the transaction is already in a block
596 // or in the memory pool:
597 CTransaction existingTx;
598 uint256 hashBlock = 0;
599 if (GetTransaction(hashTx, existingTx, hashBlock))
602 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("transaction already in block ")+hashBlock.GetHex());
603 // Not in block, but already in the memory pool; will drop
604 // through to re-relay it.
608 // push to local node
610 if (!tx.AcceptToMemoryPool(txdb))
611 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX rejected");
613 SyncWithWallets(tx, NULL, true);
615 RelayTransaction(tx, hashTx);
617 return hashTx.GetHex();
620 Value createmultisig(const Array& params, bool fHelp)
622 if (fHelp || params.size() < 2 || params.size() > 3)
624 string msg = "createmultisig <nrequired> <'[\"key\",\"key\"]'>\n"
625 "\nCreates a multi-signature address with n signature of m keys required.\n"
626 "It returns a json object with the address and redeemScript.";
627 throw runtime_error(msg);
630 int nRequired = params[0].get_int();
631 const Array& keys = params[1].get_array();
634 // Gather public keys
636 throw runtime_error("a multisignature address must require at least one key to redeem");
637 if ((int)keys.size() < nRequired)
639 strprintf("not enough keys supplied "
640 "(got %" PRIszu " keys, but need at least %d to redeem)", keys.size(), nRequired));
641 if (keys.size() > 16)
642 throw runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number");
643 std::vector<CKey> pubkeys;
644 pubkeys.resize(keys.size());
645 for (unsigned int i = 0; i < keys.size(); i++)
647 const std::string& ks = keys[i].get_str();
649 // Case 1: Bitcoin address and we have full public key:
650 CBitcoinAddress address(ks);
651 if (address.IsValid())
654 if (!address.GetKeyID(keyID))
656 strprintf("%s does not refer to a key",ks.c_str()));
658 if (!pwalletMain->GetPubKey(keyID, vchPubKey))
660 strprintf("no full public key for address %s",ks.c_str()));
661 if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
662 throw runtime_error(" Invalid public key: "+ks);
665 // Case 2: hex public key
668 CPubKey vchPubKey(ParseHex(ks));
669 if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
670 throw runtime_error(" Invalid public key: "+ks);
674 throw runtime_error(" Invalid public key: "+ks);
678 // Construct using pay-to-script-hash:
680 inner.SetMultisig(nRequired, pubkeys);
682 if (inner.size() > MAX_SCRIPT_ELEMENT_SIZE)
684 strprintf("redeemScript exceeds size limit: %" PRIszu " > %d", inner.size(), MAX_SCRIPT_ELEMENT_SIZE));
686 CScriptID innerID = inner.GetID();
687 CBitcoinAddress address(innerID);
690 result.push_back(Pair("address", address.ToString()));
691 result.push_back(Pair("redeemScript", HexStr(inner.begin(), inner.end())));