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.
7 #include "bitcoinrpc.h"
15 using namespace json_spirit;
17 void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeHex)
20 vector<CTxDestination> addresses;
23 out.push_back(Pair("asm", scriptPubKey.ToString()));
26 out.push_back(Pair("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end())));
28 if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired))
30 out.push_back(Pair("type", GetTxnOutputType(TX_NONSTANDARD)));
34 if (type != TX_NULL_DATA)
36 out.push_back(Pair("reqSigs", nRequired));
37 out.push_back(Pair("type", GetTxnOutputType(type)));
39 if (type == TX_PUBKEY_DROP)
41 vector<valtype> vSolutions;
42 Solver(scriptPubKey, type, vSolutions);
43 out.push_back(Pair("keyVariant", HexStr(vSolutions[0])));
44 out.push_back(Pair("R", HexStr(vSolutions[1])));
46 CMalleableKeyView view;
47 if (pwalletMain->CheckOwnership(CPubKey(vSolutions[0]), CPubKey(vSolutions[1]), view))
48 out.push_back(Pair("pubkeyPair", CBitcoinAddress(view.GetMalleablePubKey()).ToString()));
53 for(const auto& addr : addresses)
54 a.push_back(CBitcoinAddress(addr).ToString());
55 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 for(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 auto mi = mapBlockIndex.find(hashBlock);
107 if (mi != mapBlockIndex.end() && (*mi).second)
109 auto 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, { 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 for(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 for(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, { array_type, obj_type });
259 Array inputs = params[0].get_array();
260 Object sendTo = params[1].get_obj();
264 for(Value& input : inputs)
266 const auto& o = input.get_obj();
267 const auto& txid_v = find_value(o, "txid");
268 if (txid_v.type() != str_type)
269 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing txid key");
270 auto txid = txid_v.get_str();
272 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
274 const auto& vout_v = find_value(o, "vout");
275 if (vout_v.type() != int_type)
276 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key");
277 int nOutput = vout_v.get_int();
279 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
281 CTxIn in(COutPoint(uint256(txid), nOutput));
282 rawTx.vin.push_back(in);
285 set<CBitcoinAddress> setAddress;
286 for(const Pair& s : sendTo)
288 // Create output destination script
289 CScript scriptPubKey;
290 CBitcoinAddress address(s.name_);
292 if (address.IsValid())
294 scriptPubKey.SetAddress(address);
296 // Don't perform duplication checking for pubkey-pair addresses
297 if (!address.IsPair())
299 if (setAddress.count(address))
300 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
301 setAddress.insert(address);
305 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid output destination: ")+s.name_);
307 auto nAmount = AmountFromValue(s.value_);
309 CTxOut out(nAmount, scriptPubKey);
310 rawTx.vout.push_back(out);
313 if (params.size() == 3)
315 // Data carrying output
316 CScript scriptPubKey;
317 scriptPubKey << OP_RETURN << ParseHex(params[2].get_str());
318 CTxOut out(0, scriptPubKey);
319 rawTx.vout.push_back(out);
322 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
324 return HexStr(ss.begin(), ss.end());
327 Value decoderawtransaction(const Array& params, bool fHelp)
329 if (fHelp || params.size() != 1)
331 "decoderawtransaction <hex string>\n"
332 "Return a JSON object representing the serialized, hex-encoded transaction.");
334 RPCTypeCheck(params, { str_type });
336 auto txData = ParseHex(params[0].get_str());
337 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
342 catch (const exception&) {
343 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
347 TxToJSON(tx, 0, result);
352 Value decodescript(const Array& params, bool fHelp)
354 if (fHelp || params.size() != 1)
356 "decodescript <hex string>\n"
357 "Decode a hex-encoded script.");
359 RPCTypeCheck(params, { str_type });
363 if (params[0].get_str().size() > 0){
364 auto scriptData = ParseHexV(params[0], "argument");
365 script = CScript(scriptData.begin(), scriptData.end());
367 // Empty scripts are valid
369 ScriptPubKeyToJSON(script, r, false);
371 r.push_back(Pair("p2sh", CBitcoinAddress(script.GetID()).ToString()));
375 Value signrawtransaction(const Array& params, bool fHelp)
377 if (fHelp || params.size() < 1 || params.size() > 4)
379 "signrawtransaction <hex string> '[{\"txid\":txid,\"vout\":n,\"scriptPubKey\":hex,\"redeemScript\":hex},...]' '[<privatekey1>,...]' [sighashtype=\"ALL\"]\n"
380 "Sign inputs for raw transaction (serialized, hex-encoded).\n"
381 "Second optional argument (may be null) is an array of previous transaction outputs that\n"
382 "this transaction depends on but may not yet be in the blockchain.\n"
383 "Third optional argument (may be null) is an array of base58-encoded private\n"
384 "keys that, if given, will be the only keys used to sign the transaction.\n"
385 "Fourth optional argument is a string that is one of six values; ALL, NONE, SINGLE or\n"
386 "ALL|ANYONECANPAY, NONE|ANYONECANPAY, SINGLE|ANYONECANPAY.\n"
387 "Returns json object with keys:\n"
388 " hex : raw transaction with signature(s) (hex-encoded string)\n"
389 " complete : 1 if transaction has a complete set of signature (0 if not)"
390 + HelpRequiringPassphrase());
392 RPCTypeCheck(params, { str_type, array_type, array_type, str_type }, true);
394 auto txData = ParseHex(params[0].get_str());
395 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
396 vector<CTransaction> txVariants;
397 while (!ssData.empty())
402 txVariants.push_back(tx);
404 catch (const exception&) {
405 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
409 if (txVariants.empty())
410 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Missing transaction");
412 // mergedTx will end up with all the signatures; it
413 // starts as a clone of the rawtx:
414 CTransaction mergedTx(txVariants[0]);
415 bool fComplete = true;
417 // Fetch previous transactions (inputs):
418 map<COutPoint, CScript> mapPrevOut;
419 for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
424 map<uint256, CTxIndex> unused;
427 // FetchInputs aborts on failure, so we go one at a time.
428 tempTx.vin.push_back(mergedTx.vin[i]);
429 tempTx.FetchInputs(txdb, unused, false, false, mapPrevTx, fInvalid);
431 // Copy results into mapPrevOut:
432 for(const auto& txin : tempTx.vin)
434 const auto& prevHash = txin.prevout.hash;
435 if (mapPrevTx.count(prevHash) && mapPrevTx[prevHash].second.vout.size()>txin.prevout.n)
436 mapPrevOut[txin.prevout] = mapPrevTx[prevHash].second.vout[txin.prevout.n].scriptPubKey;
440 bool fGivenKeys = false;
441 CBasicKeyStore tempKeystore;
442 if (params.size() > 2 && params[2].type() != null_type)
445 auto keys = params[2].get_array();
448 CBitcoinSecret vchSecret;
449 bool fGood = vchSecret.SetString(k.get_str());
451 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
454 auto secret = vchSecret.GetSecret(fCompressed);
455 key.SetSecret(secret, fCompressed);
456 tempKeystore.AddKey(key);
460 EnsureWalletIsUnlocked();
462 // Add previous txouts given in the RPC call:
463 if (params.size() > 1 && params[1].type() != null_type)
465 auto prevTxs = params[1].get_array();
466 for(auto& p : prevTxs)
468 if (p.type() != obj_type)
469 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}");
471 auto prevOut = p.get_obj();
473 RPCTypeCheck(prevOut, { {"txid", str_type}, {"vout", int_type}, {"scriptPubKey", str_type} });
475 auto txidHex = find_value(prevOut, "txid").get_str();
477 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "txid must be hexadecimal");
479 txid.SetHex(txidHex);
481 int nOut = find_value(prevOut, "vout").get_int();
483 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive");
485 auto pkHex = find_value(prevOut, "scriptPubKey").get_str();
487 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "scriptPubKey must be hexadecimal");
488 auto pkData = ParseHex(pkHex);
489 CScript scriptPubKey(pkData.begin(), pkData.end());
490 COutPoint outpoint(txid, nOut);
491 if (mapPrevOut.count(outpoint))
493 // Complain if scriptPubKey doesn't match
494 if (mapPrevOut[outpoint] != scriptPubKey)
496 string err("Previous output scriptPubKey mismatch:\n");
497 err = err + mapPrevOut[outpoint].ToString() + "\nvs:\n"+
498 scriptPubKey.ToString();
499 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
503 mapPrevOut[outpoint] = scriptPubKey;
505 // if redeemScript given and not using the local wallet (private keys
506 // given), add redeemScript to the tempKeystore so it can be signed:
507 if (fGivenKeys && scriptPubKey.IsPayToScriptHash())
509 RPCTypeCheck(prevOut, { {"txid", str_type}, {"vout", int_type}, {"scriptPubKey", str_type}, {"redeemScript",str_type} });
510 auto v = find_value(prevOut, "redeemScript");
511 if (!(v == Value::null))
513 auto rsData = ParseHexV(v, "redeemScript");
514 CScript redeemScript(rsData.begin(), rsData.end());
515 tempKeystore.AddCScript(redeemScript);
521 const auto& keystore = (fGivenKeys ? tempKeystore : *pwalletMain);
523 int nHashType = SIGHASH_ALL;
524 if (params.size() > 3 && params[3].type() != null_type)
526 static map<string, int> mapSigHashValues =
528 {"ALL", SIGHASH_ALL},
529 {"ALL|ANYONECANPAY", SIGHASH_ALL|SIGHASH_ANYONECANPAY},
530 {"NONE", SIGHASH_NONE},
531 {"NONE|ANYONECANPAY", SIGHASH_NONE|SIGHASH_ANYONECANPAY},
532 {"SINGLE", SIGHASH_SINGLE},
533 {"SINGLE|ANYONECANPAY", SIGHASH_SINGLE|SIGHASH_ANYONECANPAY}
535 auto strHashType = params[3].get_str();
536 if (mapSigHashValues.count(strHashType))
537 nHashType = mapSigHashValues[strHashType];
539 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid sighash param");
542 bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
545 for (uint32_t i = 0; i < mergedTx.vin.size(); i++)
547 auto& txin = mergedTx.vin[i];
548 if (mapPrevOut.count(txin.prevout) == 0)
553 const auto& prevPubKey = mapPrevOut[txin.prevout];
555 txin.scriptSig.clear();
556 // Only sign SIGHASH_SINGLE if there's a corresponding output:
557 if (!fHashSingle || (i < mergedTx.vout.size()))
558 SignSignature(keystore, prevPubKey, mergedTx, i, nHashType);
560 // ... and merge in other signatures:
561 for(const auto& txv : txVariants)
563 txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
565 if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, STRICT_FLAGS, 0))
570 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
572 result.push_back(Pair("hex", HexStr(ssTx.begin(), ssTx.end())));
573 result.push_back(Pair("complete", fComplete));
578 Value sendrawtransaction(const Array& params, bool fHelp)
580 if (fHelp || params.size() < 1 || params.size() > 1)
582 "sendrawtransaction <hex string>\n"
583 "Submits raw transaction (serialized, hex-encoded) to local node and network.");
585 RPCTypeCheck(params, { str_type });
587 // parse hex string from parameter
588 auto txData = ParseHex(params[0].get_str());
589 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
592 // deserialize binary data stream
596 catch (const exception&) {
597 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
599 auto hashTx = tx.GetHash();
601 // See if the transaction is already in a block
602 // or in the memory pool:
603 CTransaction existingTx;
604 uint256 hashBlock = 0;
605 if (GetTransaction(hashTx, existingTx, hashBlock))
608 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("transaction already in block ")+hashBlock.GetHex());
609 // Not in block, but already in the memory pool; will drop
610 // through to re-relay it.
614 // push to local node
616 if (!tx.AcceptToMemoryPool(txdb))
617 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX rejected");
619 SyncWithWallets(tx, NULL, true);
621 RelayTransaction(tx, hashTx);
623 return hashTx.GetHex();
626 Value createmultisig(const Array& params, bool fHelp)
628 if (fHelp || params.size() < 2 || params.size() > 3)
630 string msg = "createmultisig <nrequired> <'[\"key\",\"key\"]'>\n"
631 "\nCreates a multi-signature address with n signature of m keys required.\n"
632 "It returns a json object with the address and redeemScript.";
633 throw runtime_error(msg);
636 int nRequired = params[0].get_int();
637 const auto& keys = params[1].get_array();
639 // Gather public keys
641 throw runtime_error("a multisignature address must require at least one key to redeem");
642 if ((int)keys.size() < nRequired)
644 strprintf("not enough keys supplied "
645 "(got %" PRIszu " keys, but need at least %d to redeem)", keys.size(), nRequired));
646 if (keys.size() > 16)
647 throw runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number");
648 vector<CPubKey> pubkeys;
649 pubkeys.resize(keys.size());
650 for (unsigned int i = 0; i < keys.size(); i++)
652 const auto& ks = keys[i].get_str();
654 // Case 1: Bitcoin address and we have full public key:
655 CBitcoinAddress address(ks);
656 if (address.IsValid())
659 if (!address.GetKeyID(keyID))
661 strprintf("%s does not refer to a key",ks.c_str()));
663 if (!pwalletMain->GetPubKey(keyID, vchPubKey))
665 strprintf("no full public key for address %s",ks.c_str()));
666 if (!vchPubKey.IsFullyValid())
667 throw runtime_error(" Invalid public key: "+ks);
668 pubkeys[i] = vchPubKey;
671 // Case 2: hex public key
674 CPubKey vchPubKey(ParseHex(ks));
675 if (!vchPubKey.IsFullyValid())
676 throw runtime_error(" Invalid public key: "+ks);
677 pubkeys[i] = vchPubKey;
681 throw runtime_error(" Invalid public key: "+ks);
685 // Construct using pay-to-script-hash:
687 inner.SetMultisig(nRequired, pubkeys);
689 if (inner.size() > MAX_SCRIPT_ELEMENT_SIZE)
691 strprintf("redeemScript exceeds size limit: %" PRIszu " > %d", inner.size(), MAX_SCRIPT_ELEMENT_SIZE));
693 auto innerID = inner.GetID();
694 CBitcoinAddress address(innerID);
697 result.push_back(Pair("address", address.ToString()));
698 result.push_back(Pair("redeemScript", HexStr(inner.begin(), inner.end())));