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", (int64_t)tx.nTime));
52 entry.push_back(Pair("locktime", (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", (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", (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", (int64_t)i));
80 ScriptPubKeyToJSON(txout.scriptPubKey, o, true);
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", (int64_t)pindex->nTime));
97 entry.push_back(Pair("blocktime", (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_t 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<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 entry.push_back(Pair("spendable", out.fSpendable));
221 results.push_back(entry);
227 Value createrawtransaction(const Array& params, bool fHelp)
229 if (fHelp || params.size() != 2)
231 "createrawtransaction '[{\"txid\":txid,\"vout\":n},...]' '{address:amount,...}'\n"
232 "Create a transaction spending given inputs\n"
233 "(array of objects containing transaction id and output number),\n"
234 "sending to given address(es).\n"
235 "Returns hex-encoded raw transaction.\n"
236 "Note that the transaction's inputs are not signed, and\n"
237 "it is not stored in the wallet or transmitted to the network.");
239 RPCTypeCheck(params, list_of(array_type)(obj_type));
241 Array inputs = params[0].get_array();
242 Object sendTo = params[1].get_obj();
246 BOOST_FOREACH(Value& input, inputs)
248 const Object& o = input.get_obj();
250 const Value& txid_v = find_value(o, "txid");
251 if (txid_v.type() != str_type)
252 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing txid key");
253 string txid = txid_v.get_str();
255 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
257 const Value& vout_v = find_value(o, "vout");
258 if (vout_v.type() != int_type)
259 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key");
260 int nOutput = vout_v.get_int();
262 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
264 CTxIn in(COutPoint(uint256(txid), nOutput));
265 rawTx.vin.push_back(in);
268 set<CBitcoinAddress> setAddress;
269 BOOST_FOREACH(const Pair& s, sendTo)
271 CBitcoinAddress address(s.name_);
272 if (!address.IsValid())
273 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid NovaCoin address: ")+s.name_);
275 if (setAddress.count(address))
276 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
277 setAddress.insert(address);
279 CScript scriptPubKey;
280 scriptPubKey.SetDestination(address.Get());
281 int64_t nAmount = AmountFromValue(s.value_);
283 CTxOut out(nAmount, scriptPubKey);
284 rawTx.vout.push_back(out);
287 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
289 return HexStr(ss.begin(), ss.end());
292 Value decoderawtransaction(const Array& params, bool fHelp)
294 if (fHelp || params.size() != 1)
296 "decoderawtransaction <hex string>\n"
297 "Return a JSON object representing the serialized, hex-encoded transaction.");
299 RPCTypeCheck(params, list_of(str_type));
301 vector<unsigned char> txData(ParseHex(params[0].get_str()));
302 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
307 catch (const std::exception&) {
308 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
312 TxToJSON(tx, 0, result);
317 Value decodescript(const Array& params, bool fHelp)
319 if (fHelp || params.size() != 1)
321 "decodescript <hex string>\n"
322 "Decode a hex-encoded script.");
324 RPCTypeCheck(params, list_of(str_type));
328 if (params[0].get_str().size() > 0){
329 vector<unsigned char> scriptData(ParseHexV(params[0], "argument"));
330 script = CScript(scriptData.begin(), scriptData.end());
332 // Empty scripts are valid
334 ScriptPubKeyToJSON(script, r, false);
336 r.push_back(Pair("p2sh", CBitcoinAddress(script.GetID()).ToString()));
340 Value signrawtransaction(const Array& params, bool fHelp)
342 if (fHelp || params.size() < 1 || params.size() > 4)
344 "signrawtransaction <hex string> '[{\"txid\":txid,\"vout\":n,\"scriptPubKey\":hex,\"redeemScript\":hex},...]' '[<privatekey1>,...]' [sighashtype=\"ALL\"]\n"
345 "Sign inputs for raw transaction (serialized, hex-encoded).\n"
346 "Second optional argument (may be null) is an array of previous transaction outputs that\n"
347 "this transaction depends on but may not yet be in the blockchain.\n"
348 "Third optional argument (may be null) is an array of base58-encoded private\n"
349 "keys that, if given, will be the only keys used to sign the transaction.\n"
350 "Fourth optional argument is a string that is one of six values; ALL, NONE, SINGLE or\n"
351 "ALL|ANYONECANPAY, NONE|ANYONECANPAY, SINGLE|ANYONECANPAY.\n"
352 "Returns json object with keys:\n"
353 " hex : raw transaction with signature(s) (hex-encoded string)\n"
354 " complete : 1 if transaction has a complete set of signature (0 if not)"
355 + HelpRequiringPassphrase());
357 RPCTypeCheck(params, list_of(str_type)(array_type)(array_type)(str_type), true);
359 vector<unsigned char> txData(ParseHex(params[0].get_str()));
360 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
361 vector<CTransaction> txVariants;
362 while (!ssData.empty())
367 txVariants.push_back(tx);
369 catch (const std::exception&) {
370 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
374 if (txVariants.empty())
375 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Missing transaction");
377 // mergedTx will end up with all the signatures; it
378 // starts as a clone of the rawtx:
379 CTransaction mergedTx(txVariants[0]);
380 bool fComplete = true;
382 // Fetch previous transactions (inputs):
383 map<COutPoint, CScript> mapPrevOut;
384 for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
389 map<uint256, CTxIndex> unused;
392 // FetchInputs aborts on failure, so we go one at a time.
393 tempTx.vin.push_back(mergedTx.vin[i]);
394 tempTx.FetchInputs(txdb, unused, false, false, mapPrevTx, fInvalid);
396 // Copy results into mapPrevOut:
397 BOOST_FOREACH(const CTxIn& txin, tempTx.vin)
399 const uint256& prevHash = txin.prevout.hash;
400 if (mapPrevTx.count(prevHash) && mapPrevTx[prevHash].second.vout.size()>txin.prevout.n)
401 mapPrevOut[txin.prevout] = mapPrevTx[prevHash].second.vout[txin.prevout.n].scriptPubKey;
405 bool fGivenKeys = false;
406 CBasicKeyStore tempKeystore;
407 if (params.size() > 2 && params[2].type() != null_type)
410 Array keys = params[2].get_array();
411 BOOST_FOREACH(Value k, keys)
413 CBitcoinSecret vchSecret;
414 bool fGood = vchSecret.SetString(k.get_str());
416 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
419 CSecret secret = vchSecret.GetSecret(fCompressed);
420 key.SetSecret(secret, fCompressed);
421 tempKeystore.AddKey(key);
425 EnsureWalletIsUnlocked();
427 // Add previous txouts given in the RPC call:
428 if (params.size() > 1 && params[1].type() != null_type)
430 Array prevTxs = params[1].get_array();
431 BOOST_FOREACH(Value& p, prevTxs)
433 if (p.type() != obj_type)
434 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}");
436 Object prevOut = p.get_obj();
438 RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type));
440 string txidHex = find_value(prevOut, "txid").get_str();
442 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "txid must be hexadecimal");
444 txid.SetHex(txidHex);
446 int nOut = find_value(prevOut, "vout").get_int();
448 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive");
450 string pkHex = find_value(prevOut, "scriptPubKey").get_str();
452 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "scriptPubKey must be hexadecimal");
453 vector<unsigned char> pkData(ParseHex(pkHex));
454 CScript scriptPubKey(pkData.begin(), pkData.end());
456 COutPoint outpoint(txid, nOut);
457 if (mapPrevOut.count(outpoint))
459 // Complain if scriptPubKey doesn't match
460 if (mapPrevOut[outpoint] != scriptPubKey)
462 string err("Previous output scriptPubKey mismatch:\n");
463 err = err + mapPrevOut[outpoint].ToString() + "\nvs:\n"+
464 scriptPubKey.ToString();
465 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
469 mapPrevOut[outpoint] = scriptPubKey;
471 // if redeemScript given and not using the local wallet (private keys
472 // given), add redeemScript to the tempKeystore so it can be signed:
473 Value v = find_value(prevOut, "redeemScript");
474 if (fGivenKeys && scriptPubKey.IsPayToScriptHash())
476 RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type)("redeemScript",str_type));
477 Value v = find_value(prevOut, "redeemScript");
478 if (!(v == Value::null))
480 vector<unsigned char> rsData(ParseHexV(v, "redeemScript"));
481 CScript redeemScript(rsData.begin(), rsData.end());
482 tempKeystore.AddCScript(redeemScript);
488 const CKeyStore& keystore = (fGivenKeys ? tempKeystore : *pwalletMain);
490 int nHashType = SIGHASH_ALL;
491 if (params.size() > 3 && params[3].type() != null_type)
493 static map<string, int> mapSigHashValues =
494 boost::assign::map_list_of
495 (string("ALL"), int(SIGHASH_ALL))
496 (string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY))
497 (string("NONE"), int(SIGHASH_NONE))
498 (string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY))
499 (string("SINGLE"), int(SIGHASH_SINGLE))
500 (string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY))
502 string strHashType = params[3].get_str();
503 if (mapSigHashValues.count(strHashType))
504 nHashType = mapSigHashValues[strHashType];
506 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid sighash param");
509 bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
512 for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
514 CTxIn& txin = mergedTx.vin[i];
515 if (mapPrevOut.count(txin.prevout) == 0)
520 const CScript& prevPubKey = mapPrevOut[txin.prevout];
522 txin.scriptSig.clear();
523 // Only sign SIGHASH_SINGLE if there's a corresponding output:
524 if (!fHashSingle || (i < mergedTx.vout.size()))
525 SignSignature(keystore, prevPubKey, mergedTx, i, nHashType);
527 // ... and merge in other signatures:
528 BOOST_FOREACH(const CTransaction& txv, txVariants)
530 txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
532 if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, STRICT_FLAGS, 0))
537 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
539 result.push_back(Pair("hex", HexStr(ssTx.begin(), ssTx.end())));
540 result.push_back(Pair("complete", fComplete));
545 Value sendrawtransaction(const Array& params, bool fHelp)
547 if (fHelp || params.size() < 1 || params.size() > 1)
549 "sendrawtransaction <hex string>\n"
550 "Submits raw transaction (serialized, hex-encoded) to local node and network.");
552 RPCTypeCheck(params, list_of(str_type));
554 // parse hex string from parameter
555 vector<unsigned char> txData(ParseHex(params[0].get_str()));
556 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
559 // deserialize binary data stream
563 catch (const std::exception&) {
564 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
566 uint256 hashTx = tx.GetHash();
568 // See if the transaction is already in a block
569 // or in the memory pool:
570 CTransaction existingTx;
571 uint256 hashBlock = 0;
572 if (GetTransaction(hashTx, existingTx, hashBlock))
575 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("transaction already in block ")+hashBlock.GetHex());
576 // Not in block, but already in the memory pool; will drop
577 // through to re-relay it.
581 // push to local node
583 if (!tx.AcceptToMemoryPool(txdb))
584 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX rejected");
586 SyncWithWallets(tx, NULL, true);
588 RelayTransaction(tx, hashTx);
590 return hashTx.GetHex();
593 Value createmultisig(const Array& params, bool fHelp)
595 if (fHelp || params.size() < 2 || params.size() > 3)
597 string msg = "createmultisig <nrequired> <'[\"key\",\"key\"]'>\n"
598 "\nCreates a multi-signature address with n signature of m keys required.\n"
599 "It returns a json object with the address and redeemScript.";
600 throw runtime_error(msg);
603 int nRequired = params[0].get_int();
604 const Array& keys = params[1].get_array();
607 // Gather public keys
609 throw runtime_error("a multisignature address must require at least one key to redeem");
610 if ((int)keys.size() < nRequired)
612 strprintf("not enough keys supplied "
613 "(got %" PRIszu " keys, but need at least %d to redeem)", keys.size(), nRequired));
614 if (keys.size() > 16)
615 throw runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number");
616 std::vector<CKey> pubkeys;
617 pubkeys.resize(keys.size());
618 for (unsigned int i = 0; i < keys.size(); i++)
620 const std::string& ks = keys[i].get_str();
622 // Case 1: Bitcoin address and we have full public key:
623 CBitcoinAddress address(ks);
624 if (address.IsValid())
627 if (!address.GetKeyID(keyID))
629 strprintf("%s does not refer to a key",ks.c_str()));
631 if (!pwalletMain->GetPubKey(keyID, vchPubKey))
633 strprintf("no full public key for address %s",ks.c_str()));
634 if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
635 throw runtime_error(" Invalid public key: "+ks);
638 // Case 2: hex public key
641 CPubKey vchPubKey(ParseHex(ks));
642 if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
643 throw runtime_error(" Invalid public key: "+ks);
647 throw runtime_error(" Invalid public key: "+ks);
651 // Construct using pay-to-script-hash:
653 inner.SetMultisig(nRequired, pubkeys);
655 if (inner.size() > MAX_SCRIPT_ELEMENT_SIZE)
657 strprintf("redeemScript exceeds size limit: %" PRIszu " > %d", inner.size(), MAX_SCRIPT_ELEMENT_SIZE));
659 CScriptID innerID = inner.GetID();
660 CBitcoinAddress address(innerID);
663 result.push_back(Pair("address", address.ToString()));
664 result.push_back(Pair("redeemScript", HexStr(inner.begin(), inner.end())));