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 CCoinsViewCache &viewChain = *pcoinsTip;
376 CCoinsViewMemPool viewMempool(viewChain, mempool);
377 view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view
379 BOOST_FOREACH(const CTxIn& txin, mergedTx.vin) {
380 const uint256& prevHash = txin.prevout.hash;
382 view.GetCoins(prevHash, coins); // this is certainly allowed to fail
385 view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long
388 // Add previous txouts given in the RPC call:
389 if (params.size() > 1 && params[1].type() != null_type)
391 Array prevTxs = params[1].get_array();
392 BOOST_FOREACH(Value& p, prevTxs)
394 if (p.type() != obj_type)
395 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}");
397 Object prevOut = p.get_obj();
399 RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type));
401 string txidHex = find_value(prevOut, "txid").get_str();
403 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "txid must be hexadecimal");
405 txid.SetHex(txidHex);
407 int nOut = find_value(prevOut, "vout").get_int();
409 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive");
411 string pkHex = find_value(prevOut, "scriptPubKey").get_str();
413 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "scriptPubKey must be hexadecimal");
414 vector<unsigned char> pkData(ParseHex(pkHex));
415 CScript scriptPubKey(pkData.begin(), pkData.end());
418 if (view.GetCoins(txid, coins)) {
419 if (coins.IsAvailable(nOut) && coins.vout[nOut].scriptPubKey != scriptPubKey) {
420 string err("Previous output scriptPubKey mismatch:\n");
421 err = err + coins.vout[nOut].scriptPubKey.ToString() + "\nvs:\n"+
422 scriptPubKey.ToString();
423 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
425 // what todo if txid is known, but the actual output isn't?
427 coins.vout[nOut].scriptPubKey = scriptPubKey;
428 coins.vout[nOut].nValue = 0; // we don't know the actual output value
429 view.SetCoins(txid, coins);
433 bool fGivenKeys = false;
434 CBasicKeyStore tempKeystore;
435 if (params.size() > 2 && params[2].type() != null_type)
438 Array keys = params[2].get_array();
439 BOOST_FOREACH(Value k, keys)
441 CBitcoinSecret vchSecret;
442 bool fGood = vchSecret.SetString(k.get_str());
444 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,"Invalid private key");
447 CSecret secret = vchSecret.GetSecret(fCompressed);
448 key.SetSecret(secret, fCompressed);
449 tempKeystore.AddKey(key);
453 EnsureWalletIsUnlocked();
455 const CKeyStore& keystore = (fGivenKeys ? tempKeystore : *pwalletMain);
457 int nHashType = SIGHASH_ALL;
458 if (params.size() > 3 && params[3].type() != null_type)
460 static map<string, int> mapSigHashValues =
461 boost::assign::map_list_of
462 (string("ALL"), int(SIGHASH_ALL))
463 (string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY))
464 (string("NONE"), int(SIGHASH_NONE))
465 (string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY))
466 (string("SINGLE"), int(SIGHASH_SINGLE))
467 (string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY))
469 string strHashType = params[3].get_str();
470 if (mapSigHashValues.count(strHashType))
471 nHashType = mapSigHashValues[strHashType];
473 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid sighash param");
476 bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
479 for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
481 CTxIn& txin = mergedTx.vin[i];
483 if (!view.GetCoins(txin.prevout.hash, coins) || !coins.IsAvailable(txin.prevout.n))
488 const CScript& prevPubKey = coins.vout[txin.prevout.n].scriptPubKey;
490 txin.scriptSig.clear();
491 // Only sign SIGHASH_SINGLE if there's a corresponding output:
492 if (!fHashSingle || (i < mergedTx.vout.size()))
493 SignSignature(keystore, prevPubKey, mergedTx, i, nHashType);
495 // ... and merge in other signatures:
496 BOOST_FOREACH(const CTransaction& txv, txVariants)
498 txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
500 if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, true, true, 0))
505 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
507 result.push_back(Pair("hex", HexStr(ssTx.begin(), ssTx.end())));
508 result.push_back(Pair("complete", fComplete));
513 Value sendrawtransaction(const Array& params, bool fHelp)
515 if (fHelp || params.size() < 1 || params.size() > 1)
517 "sendrawtransaction <hex string>\n"
518 "Submits raw transaction (serialized, hex-encoded) to local node and network.");
520 RPCTypeCheck(params, list_of(str_type));
522 // parse hex string from parameter
523 vector<unsigned char> txData(ParseHex(params[0].get_str()));
524 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
527 // deserialize binary data stream
531 catch (std::exception &e) {
532 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
534 uint256 hashTx = tx.GetHash();
537 CCoinsViewCache &view = *pcoinsTip;
538 CCoins existingCoins;
540 fHave = view.GetCoins(hashTx, existingCoins);
542 // push to local node
543 if (!tx.AcceptToMemoryPool())
544 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX rejected");
548 if (existingCoins.nHeight < 1000000000)
549 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "transaction already in block chain");
550 // Not in block, but already in the memory pool; will drop
551 // through to re-relay it.
553 SyncWithWallets(hashTx, tx, NULL, true);
555 RelayTransaction(tx, hashTx);
557 return hashTx.GetHex();