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 Solver(scriptPubKey, type, vSolutions);
47 out.push_back(Pair("keyVariant", HexStr(vSolutions[0])));
48 out.push_back(Pair("R", HexStr(vSolutions[1])));
50 CMalleableKeyView view;
51 if (pwalletMain->CheckOwnership(CPubKey(vSolutions[0]), CPubKey(vSolutions[1]), view))
52 out.push_back(Pair("pubkeyPair", view.GetMalleablePubKey().ToString()));
57 BOOST_FOREACH(const CTxDestination& addr, addresses)
58 a.push_back(CBitcoinAddress(addr).ToString());
59 out.push_back(Pair("addresses", a));
64 out.push_back(Pair("type", GetTxnOutputType(type)));
68 void TxToJSON(const CTransaction& tx, const uint256& hashBlock, Object& entry)
70 entry.push_back(Pair("txid", tx.GetHash().GetHex()));
71 entry.push_back(Pair("version", tx.nVersion));
72 entry.push_back(Pair("time", (int64_t)tx.nTime));
73 entry.push_back(Pair("locktime", (int64_t)tx.nLockTime));
75 BOOST_FOREACH(const CTxIn& txin, tx.vin)
79 in.push_back(Pair("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
82 in.push_back(Pair("txid", txin.prevout.hash.GetHex()));
83 in.push_back(Pair("vout", (int64_t)txin.prevout.n));
85 o.push_back(Pair("asm", txin.scriptSig.ToString()));
86 o.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
87 in.push_back(Pair("scriptSig", o));
89 in.push_back(Pair("sequence", (int64_t)txin.nSequence));
92 entry.push_back(Pair("vin", vin));
94 for (unsigned int i = 0; i < tx.vout.size(); i++)
96 const CTxOut& txout = tx.vout[i];
98 out.push_back(Pair("value", ValueFromAmount(txout.nValue)));
99 out.push_back(Pair("n", (int64_t)i));
101 ScriptPubKeyToJSON(txout.scriptPubKey, o, true);
102 out.push_back(Pair("scriptPubKey", o));
105 entry.push_back(Pair("vout", vout));
109 entry.push_back(Pair("blockhash", hashBlock.GetHex()));
110 map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
111 if (mi != mapBlockIndex.end() && (*mi).second)
113 CBlockIndex* pindex = (*mi).second;
114 if (pindex->IsInMainChain())
116 entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight));
117 entry.push_back(Pair("time", (int64_t)pindex->nTime));
118 entry.push_back(Pair("blocktime", (int64_t)pindex->nTime));
121 entry.push_back(Pair("confirmations", 0));
126 Value getrawtransaction(const Array& params, bool fHelp)
128 if (fHelp || params.size() < 1 || params.size() > 2)
130 "getrawtransaction <txid> [verbose=0]\n"
131 "If verbose=0, returns a string that is\n"
132 "serialized, hex-encoded data for <txid>.\n"
133 "If verbose is non-zero, returns an Object\n"
134 "with information about <txid>.");
137 hash.SetHex(params[0].get_str());
139 bool fVerbose = false;
140 if (params.size() > 1)
141 fVerbose = (params[1].get_int() != 0);
144 uint256 hashBlock = 0;
145 if (!GetTransaction(hash, tx, hashBlock))
146 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
148 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
150 string strHex = HexStr(ssTx.begin(), ssTx.end());
156 result.push_back(Pair("hex", strHex));
157 TxToJSON(tx, hashBlock, result);
161 Value listunspent(const Array& params, bool fHelp)
163 if (fHelp || params.size() > 3)
165 "listunspent [minconf=1] [maxconf=9999999] [\"address\",...]\n"
166 "Returns array of unspent transaction outputs\n"
167 "with between minconf and maxconf (inclusive) confirmations.\n"
168 "Optionally filtered to only include txouts paid to specified addresses.\n"
169 "Results are an array of Objects, each of which has:\n"
170 "{txid, vout, scriptPubKey, amount, confirmations}");
172 RPCTypeCheck(params, list_of(int_type)(int_type)(array_type));
175 if (params.size() > 0)
176 nMinDepth = params[0].get_int();
178 int nMaxDepth = 9999999;
179 if (params.size() > 1)
180 nMaxDepth = params[1].get_int();
182 set<CBitcoinAddress> setAddress;
183 if (params.size() > 2)
185 Array inputs = params[2].get_array();
186 BOOST_FOREACH(Value& input, inputs)
188 CBitcoinAddress address(input.get_str());
189 if (!address.IsValid())
190 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid NovaCoin address: ")+input.get_str());
191 if (setAddress.count(address))
192 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str());
193 setAddress.insert(address);
198 vector<COutput> vecOutputs;
199 pwalletMain->AvailableCoins(vecOutputs, false);
200 BOOST_FOREACH(const COutput& out, vecOutputs)
202 if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
205 if(setAddress.size())
207 CTxDestination address;
208 if(!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
211 if (!setAddress.count(address))
215 int64_t nValue = out.tx->vout[out.i].nValue;
216 const CScript& pk = out.tx->vout[out.i].scriptPubKey;
218 entry.push_back(Pair("txid", out.tx->GetHash().GetHex()));
219 entry.push_back(Pair("vout", out.i));
220 CTxDestination address;
221 if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
223 entry.push_back(Pair("address", CBitcoinAddress(address).ToString()));
224 if (pwalletMain->mapAddressBook.count(address))
225 entry.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
227 entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end())));
228 if (pk.IsPayToScriptHash())
230 CTxDestination address;
231 if (ExtractDestination(pk, address))
233 const CScriptID& hash = boost::get<CScriptID>(address);
234 CScript redeemScript;
235 if (pwalletMain->GetCScript(hash, redeemScript))
236 entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end())));
239 entry.push_back(Pair("amount",ValueFromAmount(nValue)));
240 entry.push_back(Pair("confirmations",out.nDepth));
241 entry.push_back(Pair("spendable", out.fSpendable));
242 results.push_back(entry);
248 Value createrawtransaction(const Array& params, bool fHelp)
250 if (fHelp || params.size() > 3 || params.size() < 2)
252 "createrawtransaction <'[{\"txid\":txid,\"vout\":n},...]'> <'{address:amount,...}'> [hex data]\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 "optional data to add into data-carrying output.\n"
257 "Returns hex-encoded raw transaction.\n"
258 "Note that the transaction's inputs are not signed, and\n"
259 "it is not stored in the wallet or transmitted to the network.");
261 RPCTypeCheck(params, list_of(array_type)(obj_type));
263 Array inputs = params[0].get_array();
264 Object sendTo = params[1].get_obj();
268 BOOST_FOREACH(Value& input, inputs)
270 const Object& o = input.get_obj();
272 const Value& txid_v = find_value(o, "txid");
273 if (txid_v.type() != str_type)
274 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing txid key");
275 string txid = txid_v.get_str();
277 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
279 const Value& vout_v = find_value(o, "vout");
280 if (vout_v.type() != int_type)
281 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key");
282 int nOutput = vout_v.get_int();
284 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
286 CTxIn in(COutPoint(uint256(txid), nOutput));
287 rawTx.vin.push_back(in);
290 set<CBitcoinAddress> setAddress;
291 BOOST_FOREACH(const Pair& s, sendTo)
293 // Create output destination script
294 CScript scriptPubKey;
295 CBitcoinAddress address(s.name_);
296 if (!address.IsValid())
298 CMalleablePubKey mpk(s.name_);
300 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid output destination: ")+s.name_);
302 CPubKey keyVariant, R;
303 mpk.GetVariant(R, keyVariant);
304 scriptPubKey.SetDestination(R, keyVariant);
308 scriptPubKey.SetDestination(address.Get());
309 if (setAddress.count(address))
310 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
311 setAddress.insert(address);
314 int64_t nAmount = AmountFromValue(s.value_);
316 CTxOut out(nAmount, scriptPubKey);
317 rawTx.vout.push_back(out);
320 if (params.size() == 3)
322 // Data carrying output
323 CScript scriptPubKey;
324 scriptPubKey << OP_RETURN << ParseHex(params[2].get_str());
325 CTxOut out(0, scriptPubKey);
326 rawTx.vout.push_back(out);
329 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
331 return HexStr(ss.begin(), ss.end());
334 Value decoderawtransaction(const Array& params, bool fHelp)
336 if (fHelp || params.size() != 1)
338 "decoderawtransaction <hex string>\n"
339 "Return a JSON object representing the serialized, hex-encoded transaction.");
341 RPCTypeCheck(params, list_of(str_type));
343 vector<unsigned char> txData(ParseHex(params[0].get_str()));
344 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
349 catch (const std::exception&) {
350 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
354 TxToJSON(tx, 0, result);
359 Value decodescript(const Array& params, bool fHelp)
361 if (fHelp || params.size() != 1)
363 "decodescript <hex string>\n"
364 "Decode a hex-encoded script.");
366 RPCTypeCheck(params, list_of(str_type));
370 if (params[0].get_str().size() > 0){
371 vector<unsigned char> scriptData(ParseHexV(params[0], "argument"));
372 script = CScript(scriptData.begin(), scriptData.end());
374 // Empty scripts are valid
376 ScriptPubKeyToJSON(script, r, false);
378 r.push_back(Pair("p2sh", CBitcoinAddress(script.GetID()).ToString()));
382 Value signrawtransaction(const Array& params, bool fHelp)
384 if (fHelp || params.size() < 1 || params.size() > 4)
386 "signrawtransaction <hex string> '[{\"txid\":txid,\"vout\":n,\"scriptPubKey\":hex,\"redeemScript\":hex},...]' '[<privatekey1>,...]' [sighashtype=\"ALL\"]\n"
387 "Sign inputs for raw transaction (serialized, hex-encoded).\n"
388 "Second optional argument (may be null) is an array of previous transaction outputs that\n"
389 "this transaction depends on but may not yet be in the blockchain.\n"
390 "Third optional argument (may be null) is an array of base58-encoded private\n"
391 "keys that, if given, will be the only keys used to sign the transaction.\n"
392 "Fourth optional argument is a string that is one of six values; ALL, NONE, SINGLE or\n"
393 "ALL|ANYONECANPAY, NONE|ANYONECANPAY, SINGLE|ANYONECANPAY.\n"
394 "Returns json object with keys:\n"
395 " hex : raw transaction with signature(s) (hex-encoded string)\n"
396 " complete : 1 if transaction has a complete set of signature (0 if not)"
397 + HelpRequiringPassphrase());
399 RPCTypeCheck(params, list_of(str_type)(array_type)(array_type)(str_type), true);
401 vector<unsigned char> txData(ParseHex(params[0].get_str()));
402 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
403 vector<CTransaction> txVariants;
404 while (!ssData.empty())
409 txVariants.push_back(tx);
411 catch (const std::exception&) {
412 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
416 if (txVariants.empty())
417 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Missing transaction");
419 // mergedTx will end up with all the signatures; it
420 // starts as a clone of the rawtx:
421 CTransaction mergedTx(txVariants[0]);
422 bool fComplete = true;
424 // Fetch previous transactions (inputs):
425 map<COutPoint, CScript> mapPrevOut;
426 for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
431 map<uint256, CTxIndex> unused;
434 // FetchInputs aborts on failure, so we go one at a time.
435 tempTx.vin.push_back(mergedTx.vin[i]);
436 tempTx.FetchInputs(txdb, unused, false, false, mapPrevTx, fInvalid);
438 // Copy results into mapPrevOut:
439 BOOST_FOREACH(const CTxIn& txin, tempTx.vin)
441 const uint256& prevHash = txin.prevout.hash;
442 if (mapPrevTx.count(prevHash) && mapPrevTx[prevHash].second.vout.size()>txin.prevout.n)
443 mapPrevOut[txin.prevout] = mapPrevTx[prevHash].second.vout[txin.prevout.n].scriptPubKey;
447 bool fGivenKeys = false;
448 CBasicKeyStore tempKeystore;
449 if (params.size() > 2 && params[2].type() != null_type)
452 Array keys = params[2].get_array();
453 BOOST_FOREACH(Value k, keys)
455 CBitcoinSecret vchSecret;
456 bool fGood = vchSecret.SetString(k.get_str());
458 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
461 CSecret secret = vchSecret.GetSecret(fCompressed);
462 key.SetSecret(secret, fCompressed);
463 tempKeystore.AddKey(key);
467 EnsureWalletIsUnlocked();
469 // Add previous txouts given in the RPC call:
470 if (params.size() > 1 && params[1].type() != null_type)
472 Array prevTxs = params[1].get_array();
473 BOOST_FOREACH(Value& p, prevTxs)
475 if (p.type() != obj_type)
476 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}");
478 Object prevOut = p.get_obj();
480 RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type));
482 string txidHex = find_value(prevOut, "txid").get_str();
484 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "txid must be hexadecimal");
486 txid.SetHex(txidHex);
488 int nOut = find_value(prevOut, "vout").get_int();
490 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive");
492 string pkHex = find_value(prevOut, "scriptPubKey").get_str();
494 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "scriptPubKey must be hexadecimal");
495 vector<unsigned char> pkData(ParseHex(pkHex));
496 CScript scriptPubKey(pkData.begin(), pkData.end());
498 COutPoint outpoint(txid, nOut);
499 if (mapPrevOut.count(outpoint))
501 // Complain if scriptPubKey doesn't match
502 if (mapPrevOut[outpoint] != scriptPubKey)
504 string err("Previous output scriptPubKey mismatch:\n");
505 err = err + mapPrevOut[outpoint].ToString() + "\nvs:\n"+
506 scriptPubKey.ToString();
507 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
511 mapPrevOut[outpoint] = scriptPubKey;
513 // if redeemScript given and not using the local wallet (private keys
514 // given), add redeemScript to the tempKeystore so it can be signed:
515 Value v = find_value(prevOut, "redeemScript");
516 if (fGivenKeys && scriptPubKey.IsPayToScriptHash())
518 RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type)("redeemScript",str_type));
519 Value v = find_value(prevOut, "redeemScript");
520 if (!(v == Value::null))
522 vector<unsigned char> rsData(ParseHexV(v, "redeemScript"));
523 CScript redeemScript(rsData.begin(), rsData.end());
524 tempKeystore.AddCScript(redeemScript);
530 const CKeyStore& keystore = (fGivenKeys ? tempKeystore : *pwalletMain);
532 int nHashType = SIGHASH_ALL;
533 if (params.size() > 3 && params[3].type() != null_type)
535 static map<string, int> mapSigHashValues =
536 boost::assign::map_list_of
537 (string("ALL"), int(SIGHASH_ALL))
538 (string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY))
539 (string("NONE"), int(SIGHASH_NONE))
540 (string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY))
541 (string("SINGLE"), int(SIGHASH_SINGLE))
542 (string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY))
544 string strHashType = params[3].get_str();
545 if (mapSigHashValues.count(strHashType))
546 nHashType = mapSigHashValues[strHashType];
548 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid sighash param");
551 bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
554 for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
556 CTxIn& txin = mergedTx.vin[i];
557 if (mapPrevOut.count(txin.prevout) == 0)
562 const CScript& prevPubKey = mapPrevOut[txin.prevout];
564 txin.scriptSig.clear();
565 // Only sign SIGHASH_SINGLE if there's a corresponding output:
566 if (!fHashSingle || (i < mergedTx.vout.size()))
567 SignSignature(keystore, prevPubKey, mergedTx, i, nHashType);
569 // ... and merge in other signatures:
570 BOOST_FOREACH(const CTransaction& txv, txVariants)
572 txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
574 if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, STRICT_FLAGS, 0))
579 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
581 result.push_back(Pair("hex", HexStr(ssTx.begin(), ssTx.end())));
582 result.push_back(Pair("complete", fComplete));
587 Value sendrawtransaction(const Array& params, bool fHelp)
589 if (fHelp || params.size() < 1 || params.size() > 1)
591 "sendrawtransaction <hex string>\n"
592 "Submits raw transaction (serialized, hex-encoded) to local node and network.");
594 RPCTypeCheck(params, list_of(str_type));
596 // parse hex string from parameter
597 vector<unsigned char> txData(ParseHex(params[0].get_str()));
598 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
601 // deserialize binary data stream
605 catch (const std::exception&) {
606 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
608 uint256 hashTx = tx.GetHash();
610 // See if the transaction is already in a block
611 // or in the memory pool:
612 CTransaction existingTx;
613 uint256 hashBlock = 0;
614 if (GetTransaction(hashTx, existingTx, hashBlock))
617 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("transaction already in block ")+hashBlock.GetHex());
618 // Not in block, but already in the memory pool; will drop
619 // through to re-relay it.
623 // push to local node
625 if (!tx.AcceptToMemoryPool(txdb))
626 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX rejected");
628 SyncWithWallets(tx, NULL, true);
630 RelayTransaction(tx, hashTx);
632 return hashTx.GetHex();
635 Value createmultisig(const Array& params, bool fHelp)
637 if (fHelp || params.size() < 2 || params.size() > 3)
639 string msg = "createmultisig <nrequired> <'[\"key\",\"key\"]'>\n"
640 "\nCreates a multi-signature address with n signature of m keys required.\n"
641 "It returns a json object with the address and redeemScript.";
642 throw runtime_error(msg);
645 int nRequired = params[0].get_int();
646 const Array& keys = params[1].get_array();
648 // Gather public keys
650 throw runtime_error("a multisignature address must require at least one key to redeem");
651 if ((int)keys.size() < nRequired)
653 strprintf("not enough keys supplied "
654 "(got %" PRIszu " keys, but need at least %d to redeem)", keys.size(), nRequired));
655 if (keys.size() > 16)
656 throw runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number");
657 std::vector<CKey> pubkeys;
658 pubkeys.resize(keys.size());
659 for (unsigned int i = 0; i < keys.size(); i++)
661 const std::string& ks = keys[i].get_str();
663 // Case 1: Bitcoin address and we have full public key:
664 CBitcoinAddress address(ks);
665 if (address.IsValid())
668 if (!address.GetKeyID(keyID))
670 strprintf("%s does not refer to a key",ks.c_str()));
672 if (!pwalletMain->GetPubKey(keyID, vchPubKey))
674 strprintf("no full public key for address %s",ks.c_str()));
675 if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
676 throw runtime_error(" Invalid public key: "+ks);
679 // Case 2: hex public key
682 CPubKey vchPubKey(ParseHex(ks));
683 if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
684 throw runtime_error(" Invalid public key: "+ks);
688 throw runtime_error(" Invalid public key: "+ks);
692 // Construct using pay-to-script-hash:
694 inner.SetMultisig(nRequired, pubkeys);
696 if (inner.size() > MAX_SCRIPT_ELEMENT_SIZE)
698 strprintf("redeemScript exceeds size limit: %" PRIszu " > %d", inner.size(), MAX_SCRIPT_ELEMENT_SIZE));
700 CScriptID innerID = inner.GetID();
701 CBitcoinAddress address(innerID);
704 result.push_back(Pair("address", address.ToString()));
705 result.push_back(Pair("redeemScript", HexStr(inner.begin(), inner.end())));