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", CBitcoinAddress(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_);
297 if (address.IsValid())
299 scriptPubKey.SetAddress(address);
301 // Don't perform duplication checking for pubkey-pair addresses
302 if (!address.IsPair())
304 if (setAddress.count(address))
305 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
306 setAddress.insert(address);
310 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid output destination: ")+s.name_);
312 int64_t nAmount = AmountFromValue(s.value_);
314 CTxOut out(nAmount, scriptPubKey);
315 rawTx.vout.push_back(out);
318 if (params.size() == 3)
320 // Data carrying output
321 CScript scriptPubKey;
322 scriptPubKey << OP_RETURN << ParseHex(params[2].get_str());
323 CTxOut out(0, scriptPubKey);
324 rawTx.vout.push_back(out);
327 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
329 return HexStr(ss.begin(), ss.end());
332 Value decoderawtransaction(const Array& params, bool fHelp)
334 if (fHelp || params.size() != 1)
336 "decoderawtransaction <hex string>\n"
337 "Return a JSON object representing the serialized, hex-encoded transaction.");
339 RPCTypeCheck(params, list_of(str_type));
341 vector<unsigned char> txData(ParseHex(params[0].get_str()));
342 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
347 catch (const std::exception&) {
348 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
352 TxToJSON(tx, 0, result);
357 Value decodescript(const Array& params, bool fHelp)
359 if (fHelp || params.size() != 1)
361 "decodescript <hex string>\n"
362 "Decode a hex-encoded script.");
364 RPCTypeCheck(params, list_of(str_type));
368 if (params[0].get_str().size() > 0){
369 vector<unsigned char> scriptData(ParseHexV(params[0], "argument"));
370 script = CScript(scriptData.begin(), scriptData.end());
372 // Empty scripts are valid
374 ScriptPubKeyToJSON(script, r, false);
376 r.push_back(Pair("p2sh", CBitcoinAddress(script.GetID()).ToString()));
380 Value signrawtransaction(const Array& params, bool fHelp)
382 if (fHelp || params.size() < 1 || params.size() > 4)
384 "signrawtransaction <hex string> '[{\"txid\":txid,\"vout\":n,\"scriptPubKey\":hex,\"redeemScript\":hex},...]' '[<privatekey1>,...]' [sighashtype=\"ALL\"]\n"
385 "Sign inputs for raw transaction (serialized, hex-encoded).\n"
386 "Second optional argument (may be null) is an array of previous transaction outputs that\n"
387 "this transaction depends on but may not yet be in the blockchain.\n"
388 "Third optional argument (may be null) is an array of base58-encoded private\n"
389 "keys that, if given, will be the only keys used to sign the transaction.\n"
390 "Fourth optional argument is a string that is one of six values; ALL, NONE, SINGLE or\n"
391 "ALL|ANYONECANPAY, NONE|ANYONECANPAY, SINGLE|ANYONECANPAY.\n"
392 "Returns json object with keys:\n"
393 " hex : raw transaction with signature(s) (hex-encoded string)\n"
394 " complete : 1 if transaction has a complete set of signature (0 if not)"
395 + HelpRequiringPassphrase());
397 RPCTypeCheck(params, list_of(str_type)(array_type)(array_type)(str_type), true);
399 vector<unsigned char> txData(ParseHex(params[0].get_str()));
400 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
401 vector<CTransaction> txVariants;
402 while (!ssData.empty())
407 txVariants.push_back(tx);
409 catch (const std::exception&) {
410 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
414 if (txVariants.empty())
415 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Missing transaction");
417 // mergedTx will end up with all the signatures; it
418 // starts as a clone of the rawtx:
419 CTransaction mergedTx(txVariants[0]);
420 bool fComplete = true;
422 // Fetch previous transactions (inputs):
423 map<COutPoint, CScript> mapPrevOut;
424 for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
429 map<uint256, CTxIndex> unused;
432 // FetchInputs aborts on failure, so we go one at a time.
433 tempTx.vin.push_back(mergedTx.vin[i]);
434 tempTx.FetchInputs(txdb, unused, false, false, mapPrevTx, fInvalid);
436 // Copy results into mapPrevOut:
437 BOOST_FOREACH(const CTxIn& txin, tempTx.vin)
439 const uint256& prevHash = txin.prevout.hash;
440 if (mapPrevTx.count(prevHash) && mapPrevTx[prevHash].second.vout.size()>txin.prevout.n)
441 mapPrevOut[txin.prevout] = mapPrevTx[prevHash].second.vout[txin.prevout.n].scriptPubKey;
445 bool fGivenKeys = false;
446 CBasicKeyStore tempKeystore;
447 if (params.size() > 2 && params[2].type() != null_type)
450 Array keys = params[2].get_array();
451 BOOST_FOREACH(Value k, keys)
453 CBitcoinSecret vchSecret;
454 bool fGood = vchSecret.SetString(k.get_str());
456 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
459 CSecret secret = vchSecret.GetSecret(fCompressed);
460 key.SetSecret(secret, fCompressed);
461 tempKeystore.AddKey(key);
465 EnsureWalletIsUnlocked();
467 // Add previous txouts given in the RPC call:
468 if (params.size() > 1 && params[1].type() != null_type)
470 Array prevTxs = params[1].get_array();
471 BOOST_FOREACH(Value& p, prevTxs)
473 if (p.type() != obj_type)
474 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}");
476 Object prevOut = p.get_obj();
478 RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type));
480 string txidHex = find_value(prevOut, "txid").get_str();
482 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "txid must be hexadecimal");
484 txid.SetHex(txidHex);
486 int nOut = find_value(prevOut, "vout").get_int();
488 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive");
490 string pkHex = find_value(prevOut, "scriptPubKey").get_str();
492 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "scriptPubKey must be hexadecimal");
493 vector<unsigned char> pkData(ParseHex(pkHex));
494 CScript scriptPubKey(pkData.begin(), pkData.end());
496 COutPoint outpoint(txid, nOut);
497 if (mapPrevOut.count(outpoint))
499 // Complain if scriptPubKey doesn't match
500 if (mapPrevOut[outpoint] != scriptPubKey)
502 string err("Previous output scriptPubKey mismatch:\n");
503 err = err + mapPrevOut[outpoint].ToString() + "\nvs:\n"+
504 scriptPubKey.ToString();
505 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
509 mapPrevOut[outpoint] = scriptPubKey;
511 // if redeemScript given and not using the local wallet (private keys
512 // given), add redeemScript to the tempKeystore so it can be signed:
513 Value v = find_value(prevOut, "redeemScript");
514 if (fGivenKeys && scriptPubKey.IsPayToScriptHash())
516 RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type)("redeemScript",str_type));
517 Value v = find_value(prevOut, "redeemScript");
518 if (!(v == Value::null))
520 vector<unsigned char> rsData(ParseHexV(v, "redeemScript"));
521 CScript redeemScript(rsData.begin(), rsData.end());
522 tempKeystore.AddCScript(redeemScript);
528 const CKeyStore& keystore = (fGivenKeys ? tempKeystore : *pwalletMain);
530 int nHashType = SIGHASH_ALL;
531 if (params.size() > 3 && params[3].type() != null_type)
533 static map<string, int> mapSigHashValues =
534 boost::assign::map_list_of
535 (string("ALL"), int(SIGHASH_ALL))
536 (string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY))
537 (string("NONE"), int(SIGHASH_NONE))
538 (string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY))
539 (string("SINGLE"), int(SIGHASH_SINGLE))
540 (string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY))
542 string strHashType = params[3].get_str();
543 if (mapSigHashValues.count(strHashType))
544 nHashType = mapSigHashValues[strHashType];
546 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid sighash param");
549 bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
552 for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
554 CTxIn& txin = mergedTx.vin[i];
555 if (mapPrevOut.count(txin.prevout) == 0)
560 const CScript& prevPubKey = mapPrevOut[txin.prevout];
562 txin.scriptSig.clear();
563 // Only sign SIGHASH_SINGLE if there's a corresponding output:
564 if (!fHashSingle || (i < mergedTx.vout.size()))
565 SignSignature(keystore, prevPubKey, mergedTx, i, nHashType);
567 // ... and merge in other signatures:
568 BOOST_FOREACH(const CTransaction& txv, txVariants)
570 txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
572 if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, STRICT_FLAGS, 0))
577 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
579 result.push_back(Pair("hex", HexStr(ssTx.begin(), ssTx.end())));
580 result.push_back(Pair("complete", fComplete));
585 Value sendrawtransaction(const Array& params, bool fHelp)
587 if (fHelp || params.size() < 1 || params.size() > 1)
589 "sendrawtransaction <hex string>\n"
590 "Submits raw transaction (serialized, hex-encoded) to local node and network.");
592 RPCTypeCheck(params, list_of(str_type));
594 // parse hex string from parameter
595 vector<unsigned char> txData(ParseHex(params[0].get_str()));
596 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
599 // deserialize binary data stream
603 catch (const std::exception&) {
604 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
606 uint256 hashTx = tx.GetHash();
608 // See if the transaction is already in a block
609 // or in the memory pool:
610 CTransaction existingTx;
611 uint256 hashBlock = 0;
612 if (GetTransaction(hashTx, existingTx, hashBlock))
615 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("transaction already in block ")+hashBlock.GetHex());
616 // Not in block, but already in the memory pool; will drop
617 // through to re-relay it.
621 // push to local node
623 if (!tx.AcceptToMemoryPool(txdb))
624 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX rejected");
626 SyncWithWallets(tx, NULL, true);
628 RelayTransaction(tx, hashTx);
630 return hashTx.GetHex();
633 Value createmultisig(const Array& params, bool fHelp)
635 if (fHelp || params.size() < 2 || params.size() > 3)
637 string msg = "createmultisig <nrequired> <'[\"key\",\"key\"]'>\n"
638 "\nCreates a multi-signature address with n signature of m keys required.\n"
639 "It returns a json object with the address and redeemScript.";
640 throw runtime_error(msg);
643 int nRequired = params[0].get_int();
644 const Array& keys = params[1].get_array();
646 // Gather public keys
648 throw runtime_error("a multisignature address must require at least one key to redeem");
649 if ((int)keys.size() < nRequired)
651 strprintf("not enough keys supplied "
652 "(got %" PRIszu " keys, but need at least %d to redeem)", keys.size(), nRequired));
653 if (keys.size() > 16)
654 throw runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number");
655 std::vector<CPubKey> pubkeys;
656 pubkeys.resize(keys.size());
657 for (unsigned int i = 0; i < keys.size(); i++)
659 const std::string& ks = keys[i].get_str();
661 // Case 1: Bitcoin address and we have full public key:
662 CBitcoinAddress address(ks);
663 if (address.IsValid())
666 if (!address.GetKeyID(keyID))
668 strprintf("%s does not refer to a key",ks.c_str()));
670 if (!pwalletMain->GetPubKey(keyID, vchPubKey))
672 strprintf("no full public key for address %s",ks.c_str()));
673 if (!vchPubKey.IsFullyValid())
674 throw runtime_error(" Invalid public key: "+ks);
675 pubkeys[i] = vchPubKey;
678 // Case 2: hex public key
681 CPubKey vchPubKey(ParseHex(ks));
682 if (!vchPubKey.IsFullyValid())
683 throw runtime_error(" Invalid public key: "+ks);
684 pubkeys[i] = vchPubKey;
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())));