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", (boost::int64_t)tx.nTime));
52 entry.push_back(Pair("locktime", (boost::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", (boost::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", (boost::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", (boost::int64_t)i));
80 ScriptPubKeyToJSON(txout.scriptPubKey, o, false);
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", (boost::int64_t)pindex->nTime));
97 entry.push_back(Pair("blocktime", (boost::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, true))
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 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 entry.push_back(Pair("amount",ValueFromAmount(nValue)));
208 entry.push_back(Pair("confirmations",out.nDepth));
209 results.push_back(entry);
215 Value decodescript(const Array& params, bool fHelp)
217 if (fHelp || params.size() != 1)
219 "decodescript <hex string>\n"
220 "Decode a hex-encoded script.");
222 RPCTypeCheck(params, list_of(str_type));
226 if (params[0].get_str().size() > 0){
227 vector<unsigned char> scriptData(ParseHexV(params[0], "argument"));
228 script = CScript(scriptData.begin(), scriptData.end());
230 // Empty scripts are valid
232 ScriptPubKeyToJSON(script, r, false);
234 r.push_back(Pair("p2sh", CBitcoinAddress(script.GetID()).ToString()));
238 Value createrawtransaction(const Array& params, bool fHelp)
240 if (fHelp || params.size() != 2)
242 "createrawtransaction [{\"txid\":txid,\"vout\":n},...] {address:amount,...}\n"
243 "Create a transaction spending given inputs\n"
244 "(array of objects containing transaction id and output number),\n"
245 "sending to given address(es).\n"
246 "Returns hex-encoded raw transaction.\n"
247 "Note that the transaction's inputs are not signed, and\n"
248 "it is not stored in the wallet or transmitted to the network.");
250 RPCTypeCheck(params, list_of(array_type)(obj_type));
252 Array inputs = params[0].get_array();
253 Object sendTo = params[1].get_obj();
257 BOOST_FOREACH(Value& input, inputs)
259 const Object& o = input.get_obj();
261 const Value& txid_v = find_value(o, "txid");
262 if (txid_v.type() != str_type)
263 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing txid key");
264 string txid = txid_v.get_str();
266 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
268 const Value& vout_v = find_value(o, "vout");
269 if (vout_v.type() != int_type)
270 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key");
271 int nOutput = vout_v.get_int();
273 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
275 CTxIn in(COutPoint(uint256(txid), nOutput));
276 rawTx.vin.push_back(in);
279 set<CBitcoinAddress> setAddress;
280 BOOST_FOREACH(const Pair& s, sendTo)
282 CBitcoinAddress address(s.name_);
283 if (!address.IsValid())
284 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+s.name_);
286 if (setAddress.count(address))
287 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
288 setAddress.insert(address);
290 CScript scriptPubKey;
291 scriptPubKey.SetDestination(address.Get());
292 int64 nAmount = AmountFromValue(s.value_);
294 CTxOut out(nAmount, scriptPubKey);
295 rawTx.vout.push_back(out);
298 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
300 return HexStr(ss.begin(), ss.end());
303 Value decoderawtransaction(const Array& params, bool fHelp)
305 if (fHelp || params.size() != 1)
307 "decoderawtransaction <hex string>\n"
308 "Return a JSON object representing the serialized, hex-encoded transaction.");
310 RPCTypeCheck(params, list_of(str_type));
312 vector<unsigned char> txData(ParseHex(params[0].get_str()));
313 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
318 catch (std::exception &e) {
319 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
323 TxToJSON(tx, 0, result);
328 Value signrawtransaction(const Array& params, bool fHelp)
330 if (fHelp || params.size() < 1 || params.size() > 4)
332 "signrawtransaction <hex string> [{\"txid\":txid,\"vout\":n,\"scriptPubKey\":hex},...] [<privatekey1>,...] [sighashtype=\"ALL\"]\n"
333 "Sign inputs for raw transaction (serialized, hex-encoded).\n"
334 "Second optional argument (may be null) is an array of previous transaction outputs that\n"
335 "this transaction depends on but may not yet be in the blockchain.\n"
336 "Third optional argument (may be null) is an array of base58-encoded private\n"
337 "keys that, if given, will be the only keys used to sign the transaction.\n"
338 "Fourth optional argument is a string that is one of six values; ALL, NONE, SINGLE or\n"
339 "ALL|ANYONECANPAY, NONE|ANYONECANPAY, SINGLE|ANYONECANPAY.\n"
340 "Returns json object with keys:\n"
341 " hex : raw transaction with signature(s) (hex-encoded string)\n"
342 " complete : 1 if transaction has a complete set of signature (0 if not)"
343 + HelpRequiringPassphrase());
345 RPCTypeCheck(params, list_of(str_type)(array_type)(array_type)(str_type), true);
347 vector<unsigned char> txData(ParseHex(params[0].get_str()));
348 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
349 vector<CTransaction> txVariants;
350 while (!ssData.empty())
355 txVariants.push_back(tx);
357 catch (std::exception &e) {
358 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
362 if (txVariants.empty())
363 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Missing transaction");
365 // mergedTx will end up with all the signatures; it
366 // starts as a clone of the rawtx:
367 CTransaction mergedTx(txVariants[0]);
368 bool fComplete = true;
370 // Fetch previous transactions (inputs):
371 CCoinsView viewDummy;
372 CCoinsViewCache view(viewDummy);
375 CCoinsDB coinsdb("r");
376 CCoinsViewDB viewDB(coinsdb);
377 CCoinsViewMemPool viewMempool(viewDB, mempool);
378 view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view
380 BOOST_FOREACH(const CTxIn& txin, mergedTx.vin) {
381 const uint256& prevHash = txin.prevout.hash;
383 view.GetCoins(prevHash, coins); // this is certainly allowed to fail
386 view.SetBackend(viewDummy); // switch back to avoid locking db/mempool too long
389 // Add previous txouts given in the RPC call:
390 if (params.size() > 1 && params[1].type() != null_type)
392 Array prevTxs = params[1].get_array();
393 BOOST_FOREACH(Value& p, prevTxs)
395 if (p.type() != obj_type)
396 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}");
398 Object prevOut = p.get_obj();
400 RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type));
402 string txidHex = find_value(prevOut, "txid").get_str();
404 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "txid must be hexadecimal");
406 txid.SetHex(txidHex);
408 int nOut = find_value(prevOut, "vout").get_int();
410 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive");
412 string pkHex = find_value(prevOut, "scriptPubKey").get_str();
414 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "scriptPubKey must be hexadecimal");
415 vector<unsigned char> pkData(ParseHex(pkHex));
416 CScript scriptPubKey(pkData.begin(), pkData.end());
419 if (view.GetCoins(txid, coins)) {
420 if (coins.IsAvailable(nOut) && coins.vout[nOut].scriptPubKey != scriptPubKey) {
421 string err("Previous output scriptPubKey mismatch:\n");
422 err = err + coins.vout[nOut].scriptPubKey.ToString() + "\nvs:\n"+
423 scriptPubKey.ToString();
424 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
426 // what todo if txid is known, but the actual output isn't?
428 coins.vout[nOut].scriptPubKey = scriptPubKey;
429 coins.vout[nOut].nValue = 0; // we don't know the actual output value
430 view.SetCoins(txid, coins);
434 bool fGivenKeys = false;
435 CBasicKeyStore tempKeystore;
436 if (params.size() > 2 && params[2].type() != null_type)
439 Array keys = params[2].get_array();
440 BOOST_FOREACH(Value k, keys)
442 CBitcoinSecret vchSecret;
443 bool fGood = vchSecret.SetString(k.get_str());
445 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,"Invalid private key");
448 CSecret secret = vchSecret.GetSecret(fCompressed);
449 key.SetSecret(secret, fCompressed);
450 tempKeystore.AddKey(key);
454 EnsureWalletIsUnlocked();
456 const CKeyStore& keystore = (fGivenKeys ? tempKeystore : *pwalletMain);
458 int nHashType = SIGHASH_ALL;
459 if (params.size() > 3 && params[3].type() != null_type)
461 static map<string, int> mapSigHashValues =
462 boost::assign::map_list_of
463 (string("ALL"), int(SIGHASH_ALL))
464 (string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY))
465 (string("NONE"), int(SIGHASH_NONE))
466 (string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY))
467 (string("SINGLE"), int(SIGHASH_SINGLE))
468 (string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY))
470 string strHashType = params[3].get_str();
471 if (mapSigHashValues.count(strHashType))
472 nHashType = mapSigHashValues[strHashType];
474 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid sighash param");
477 bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
480 for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
482 CTxIn& txin = mergedTx.vin[i];
484 if (!view.GetCoins(txin.prevout.hash, coins) || !coins.IsAvailable(txin.prevout.n))
489 const CScript& prevPubKey = coins.vout[txin.prevout.n].scriptPubKey;
491 txin.scriptSig.clear();
492 // Only sign SIGHASH_SINGLE if there's a corresponding output:
493 if (!fHashSingle || (i < mergedTx.vout.size()))
494 SignSignature(keystore, prevPubKey, mergedTx, i, nHashType);
496 // ... and merge in other signatures:
497 BOOST_FOREACH(const CTransaction& txv, txVariants)
499 txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
501 if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, true, true, 0))
506 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
508 result.push_back(Pair("hex", HexStr(ssTx.begin(), ssTx.end())));
509 result.push_back(Pair("complete", fComplete));
514 Value sendrawtransaction(const Array& params, bool fHelp)
516 if (fHelp || params.size() < 1 || params.size() > 1)
518 "sendrawtransaction <hex string>\n"
519 "Submits raw transaction (serialized, hex-encoded) to local node and network.");
521 RPCTypeCheck(params, list_of(str_type));
523 // parse hex string from parameter
524 vector<unsigned char> txData(ParseHex(params[0].get_str()));
525 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
528 // deserialize binary data stream
532 catch (std::exception &e) {
533 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
535 uint256 hashTx = tx.GetHash();
538 CCoins existingCoins;
540 CCoinsDB coinsdb("r");
542 CCoinsViewDB coinsviewDB(coinsdb);
543 CCoinsViewMemPool coinsview(coinsviewDB, mempool);
544 fHave = coinsview.GetCoins(hashTx, existingCoins);
547 // push to local node
548 if (!tx.AcceptToMemoryPool(coinsdb))
549 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX rejected");
553 if (existingCoins.nHeight < 1000000000)
554 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "transaction already in block chain");
555 // Not in block, but already in the memory pool; will drop
556 // through to re-relay it.
558 SyncWithWallets(tx, NULL, true);
560 RelayTransaction(tx, hashTx);
562 return hashTx.GetHex();