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))
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 createrawtransaction(const Array& params, bool fHelp)
217 if (fHelp || params.size() != 2)
219 "createrawtransaction [{\"txid\":txid,\"vout\":n},...] {address:amount,...}\n"
220 "Create a transaction spending given inputs\n"
221 "(array of objects containing transaction id and output number),\n"
222 "sending to given address(es).\n"
223 "Returns hex-encoded raw transaction.\n"
224 "Note that the transaction's inputs are not signed, and\n"
225 "it is not stored in the wallet or transmitted to the network.");
227 RPCTypeCheck(params, list_of(array_type)(obj_type));
229 Array inputs = params[0].get_array();
230 Object sendTo = params[1].get_obj();
234 BOOST_FOREACH(Value& input, inputs)
236 const Object& o = input.get_obj();
238 const Value& txid_v = find_value(o, "txid");
239 if (txid_v.type() != str_type)
240 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing txid key");
241 string txid = txid_v.get_str();
243 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
245 const Value& vout_v = find_value(o, "vout");
246 if (vout_v.type() != int_type)
247 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key");
248 int nOutput = vout_v.get_int();
250 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
252 CTxIn in(COutPoint(uint256(txid), nOutput));
253 rawTx.vin.push_back(in);
256 set<CBitcoinAddress> setAddress;
257 BOOST_FOREACH(const Pair& s, sendTo)
259 CBitcoinAddress address(s.name_);
260 if (!address.IsValid())
261 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid NovaCoin address: ")+s.name_);
263 if (setAddress.count(address))
264 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
265 setAddress.insert(address);
267 CScript scriptPubKey;
268 scriptPubKey.SetDestination(address.Get());
269 int64 nAmount = AmountFromValue(s.value_);
271 CTxOut out(nAmount, scriptPubKey);
272 rawTx.vout.push_back(out);
275 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
277 return HexStr(ss.begin(), ss.end());
280 Value decoderawtransaction(const Array& params, bool fHelp)
282 if (fHelp || params.size() != 1)
284 "decoderawtransaction <hex string>\n"
285 "Return a JSON object representing the serialized, hex-encoded transaction.");
287 RPCTypeCheck(params, list_of(str_type));
289 vector<unsigned char> txData(ParseHex(params[0].get_str()));
290 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
295 catch (std::exception &e) {
296 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
300 TxToJSON(tx, 0, result);
305 Value decodescript(const Array& params, bool fHelp)
307 if (fHelp || params.size() != 1)
309 "decodescript <hex string>\n"
310 "Decode a hex-encoded script.");
312 RPCTypeCheck(params, list_of(str_type));
316 if (params[0].get_str().size() > 0){
317 vector<unsigned char> scriptData(ParseHexV(params[0], "argument"));
318 script = CScript(scriptData.begin(), scriptData.end());
320 // Empty scripts are valid
322 ScriptPubKeyToJSON(script, r, false);
324 r.push_back(Pair("p2sh", CBitcoinAddress(script.GetID()).ToString()));
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 map<COutPoint, CScript> mapPrevOut;
372 for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
377 map<uint256, CTxIndex> unused;
380 // FetchInputs aborts on failure, so we go one at a time.
381 tempTx.vin.push_back(mergedTx.vin[i]);
382 tempTx.FetchInputs(txdb, unused, false, false, mapPrevTx, fInvalid);
384 // Copy results into mapPrevOut:
385 BOOST_FOREACH(const CTxIn& txin, tempTx.vin)
387 const uint256& prevHash = txin.prevout.hash;
388 if (mapPrevTx.count(prevHash) && mapPrevTx[prevHash].second.vout.size()>txin.prevout.n)
389 mapPrevOut[txin.prevout] = mapPrevTx[prevHash].second.vout[txin.prevout.n].scriptPubKey;
393 // Add previous txouts given in the RPC call:
394 if (params.size() > 1 && params[1].type() != null_type)
396 Array prevTxs = params[1].get_array();
397 BOOST_FOREACH(Value& p, prevTxs)
399 if (p.type() != obj_type)
400 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}");
402 Object prevOut = p.get_obj();
404 RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type));
406 string txidHex = find_value(prevOut, "txid").get_str();
408 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "txid must be hexadecimal");
410 txid.SetHex(txidHex);
412 int nOut = find_value(prevOut, "vout").get_int();
414 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive");
416 string pkHex = find_value(prevOut, "scriptPubKey").get_str();
418 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "scriptPubKey must be hexadecimal");
419 vector<unsigned char> pkData(ParseHex(pkHex));
420 CScript scriptPubKey(pkData.begin(), pkData.end());
422 COutPoint outpoint(txid, nOut);
423 if (mapPrevOut.count(outpoint))
425 // Complain if scriptPubKey doesn't match
426 if (mapPrevOut[outpoint] != scriptPubKey)
428 string err("Previous output scriptPubKey mismatch:\n");
429 err = err + mapPrevOut[outpoint].ToString() + "\nvs:\n"+
430 scriptPubKey.ToString();
431 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
435 mapPrevOut[outpoint] = scriptPubKey;
439 bool fGivenKeys = false;
440 CBasicKeyStore tempKeystore;
441 if (params.size() > 2 && params[2].type() != null_type)
444 Array keys = params[2].get_array();
445 BOOST_FOREACH(Value k, keys)
447 CBitcoinSecret vchSecret;
448 bool fGood = vchSecret.SetString(k.get_str());
450 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,"Invalid private key");
453 CSecret secret = vchSecret.GetSecret(fCompressed);
454 key.SetSecret(secret, fCompressed);
455 tempKeystore.AddKey(key);
459 EnsureWalletIsUnlocked();
461 const CKeyStore& keystore = (fGivenKeys ? tempKeystore : *pwalletMain);
463 int nHashType = SIGHASH_ALL;
464 if (params.size() > 3 && params[3].type() != null_type)
466 static map<string, int> mapSigHashValues =
467 boost::assign::map_list_of
468 (string("ALL"), int(SIGHASH_ALL))
469 (string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY))
470 (string("NONE"), int(SIGHASH_NONE))
471 (string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY))
472 (string("SINGLE"), int(SIGHASH_SINGLE))
473 (string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY))
475 string strHashType = params[3].get_str();
476 if (mapSigHashValues.count(strHashType))
477 nHashType = mapSigHashValues[strHashType];
479 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid sighash param");
482 bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
485 for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
487 CTxIn& txin = mergedTx.vin[i];
488 if (mapPrevOut.count(txin.prevout) == 0)
493 const CScript& prevPubKey = mapPrevOut[txin.prevout];
495 txin.scriptSig.clear();
496 // Only sign SIGHASH_SINGLE if there's a corresponding output:
497 if (!fHashSingle || (i < mergedTx.vout.size()))
498 SignSignature(keystore, prevPubKey, mergedTx, i, nHashType);
500 // ... and merge in other signatures:
501 BOOST_FOREACH(const CTransaction& txv, txVariants)
503 txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
505 if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, true, 0))
510 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
512 result.push_back(Pair("hex", HexStr(ssTx.begin(), ssTx.end())));
513 result.push_back(Pair("complete", fComplete));
518 Value sendrawtransaction(const Array& params, bool fHelp)
520 if (fHelp || params.size() < 1 || params.size() > 1)
522 "sendrawtransaction <hex string>\n"
523 "Submits raw transaction (serialized, hex-encoded) to local node and network.");
525 RPCTypeCheck(params, list_of(str_type));
527 // parse hex string from parameter
528 vector<unsigned char> txData(ParseHex(params[0].get_str()));
529 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
532 // deserialize binary data stream
536 catch (std::exception &e) {
537 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
539 uint256 hashTx = tx.GetHash();
541 // See if the transaction is already in a block
542 // or in the memory pool:
543 CTransaction existingTx;
544 uint256 hashBlock = 0;
545 if (GetTransaction(hashTx, existingTx, hashBlock))
548 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("transaction already in block ")+hashBlock.GetHex());
549 // Not in block, but already in the memory pool; will drop
550 // through to re-relay it.
554 // push to local node
556 if (!tx.AcceptToMemoryPool(txdb))
557 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX rejected");
559 SyncWithWallets(tx, NULL, true);
561 RelayTransaction(tx, hashTx);
563 return hashTx.GetHex();