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)
24 vector<CTxDestination> addresses;
27 out.push_back(Pair("asm", scriptPubKey.ToString()));
28 out.push_back(Pair("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end())));
30 if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired))
32 out.push_back(Pair("type", GetTxnOutputType(TX_NONSTANDARD)));
36 out.push_back(Pair("reqSigs", nRequired));
37 out.push_back(Pair("type", GetTxnOutputType(type)));
40 BOOST_FOREACH(const CTxDestination& addr, addresses)
41 a.push_back(CBitcoinAddress(addr).ToString());
42 out.push_back(Pair("addresses", a));
45 void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry)
47 entry.push_back(Pair("txid", tx.GetHash().GetHex()));
48 entry.push_back(Pair("version", tx.nVersion));
49 entry.push_back(Pair("time", (boost::int64_t)tx.nTime));
50 entry.push_back(Pair("locktime", (boost::int64_t)tx.nLockTime));
52 BOOST_FOREACH(const CTxIn& txin, tx.vin)
56 in.push_back(Pair("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
59 in.push_back(Pair("txid", txin.prevout.hash.GetHex()));
60 in.push_back(Pair("vout", (boost::int64_t)txin.prevout.n));
62 o.push_back(Pair("asm", txin.scriptSig.ToString()));
63 o.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
64 in.push_back(Pair("scriptSig", o));
66 in.push_back(Pair("sequence", (boost::int64_t)txin.nSequence));
69 entry.push_back(Pair("vin", vin));
71 for (unsigned int i = 0; i < tx.vout.size(); i++)
73 const CTxOut& txout = tx.vout[i];
75 out.push_back(Pair("value", ValueFromAmount(txout.nValue)));
76 out.push_back(Pair("n", (boost::int64_t)i));
78 ScriptPubKeyToJSON(txout.scriptPubKey, o);
79 out.push_back(Pair("scriptPubKey", o));
82 entry.push_back(Pair("vout", vout));
86 entry.push_back(Pair("blockhash", hashBlock.GetHex()));
87 map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
88 if (mi != mapBlockIndex.end() && (*mi).second)
90 CBlockIndex* pindex = (*mi).second;
91 if (pindex->IsInMainChain())
93 entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight));
94 entry.push_back(Pair("time", (boost::int64_t)pindex->nTime));
95 entry.push_back(Pair("blocktime", (boost::int64_t)pindex->nTime));
98 entry.push_back(Pair("confirmations", 0));
103 Value getrawtransaction(const Array& params, bool fHelp)
105 if (fHelp || params.size() < 1 || params.size() > 2)
107 "getrawtransaction <txid> [verbose=0]\n"
108 "If verbose=0, returns a string that is\n"
109 "serialized, hex-encoded data for <txid>.\n"
110 "If verbose is non-zero, returns an Object\n"
111 "with information about <txid>.");
114 hash.SetHex(params[0].get_str());
116 bool fVerbose = false;
117 if (params.size() > 1)
118 fVerbose = (params[1].get_int() != 0);
121 uint256 hashBlock = 0;
122 if (!GetTransaction(hash, tx, hashBlock))
123 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
125 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
127 string strHex = HexStr(ssTx.begin(), ssTx.end());
133 result.push_back(Pair("hex", strHex));
134 TxToJSON(tx, hashBlock, result);
138 Value listunspent(const Array& params, bool fHelp)
140 if (fHelp || params.size() > 3)
142 "listunspent [minconf=1] [maxconf=9999999] [\"address\",...]\n"
143 "Returns array of unspent transaction outputs\n"
144 "with between minconf and maxconf (inclusive) confirmations.\n"
145 "Optionally filtered to only include txouts paid to specified addresses.\n"
146 "Results are an array of Objects, each of which has:\n"
147 "{txid, vout, scriptPubKey, amount, confirmations}");
149 RPCTypeCheck(params, list_of(int_type)(int_type)(array_type));
152 if (params.size() > 0)
153 nMinDepth = params[0].get_int();
155 int nMaxDepth = 9999999;
156 if (params.size() > 1)
157 nMaxDepth = params[1].get_int();
159 set<CBitcoinAddress> setAddress;
160 if (params.size() > 2)
162 Array inputs = params[2].get_array();
163 BOOST_FOREACH(Value& input, inputs)
165 CBitcoinAddress address(input.get_str());
166 if (!address.IsValid())
167 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid NovaCoin address: ")+input.get_str());
168 if (setAddress.count(address))
169 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str());
170 setAddress.insert(address);
175 vector<COutput> vecOutputs;
176 pwalletMain->AvailableCoins(vecOutputs, false);
177 BOOST_FOREACH(const COutput& out, vecOutputs)
179 if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
182 if(setAddress.size())
184 CTxDestination address;
185 if(!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
188 if (!setAddress.count(address))
192 int64 nValue = out.tx->vout[out.i].nValue;
193 const CScript& pk = out.tx->vout[out.i].scriptPubKey;
195 entry.push_back(Pair("txid", out.tx->GetHash().GetHex()));
196 entry.push_back(Pair("vout", out.i));
197 CTxDestination address;
198 if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
200 entry.push_back(Pair("address", CBitcoinAddress(address).ToString()));
201 if (pwalletMain->mapAddressBook.count(address))
202 entry.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
204 entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end())));
205 entry.push_back(Pair("amount",ValueFromAmount(nValue)));
206 entry.push_back(Pair("confirmations",out.nDepth));
207 results.push_back(entry);
213 Value createrawtransaction(const Array& params, bool fHelp)
215 if (fHelp || params.size() != 2)
217 "createrawtransaction [{\"txid\":txid,\"vout\":n},...] {address:amount,...}\n"
218 "Create a transaction spending given inputs\n"
219 "(array of objects containing transaction id and output number),\n"
220 "sending to given address(es).\n"
221 "Returns hex-encoded raw transaction.\n"
222 "Note that the transaction's inputs are not signed, and\n"
223 "it is not stored in the wallet or transmitted to the network.");
225 RPCTypeCheck(params, list_of(array_type)(obj_type));
227 Array inputs = params[0].get_array();
228 Object sendTo = params[1].get_obj();
232 BOOST_FOREACH(Value& input, inputs)
234 const Object& o = input.get_obj();
236 const Value& txid_v = find_value(o, "txid");
237 if (txid_v.type() != str_type)
238 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing txid key");
239 string txid = txid_v.get_str();
241 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
243 const Value& vout_v = find_value(o, "vout");
244 if (vout_v.type() != int_type)
245 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key");
246 int nOutput = vout_v.get_int();
248 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
250 CTxIn in(COutPoint(uint256(txid), nOutput));
251 rawTx.vin.push_back(in);
254 set<CBitcoinAddress> setAddress;
255 BOOST_FOREACH(const Pair& s, sendTo)
257 CBitcoinAddress address(s.name_);
258 if (!address.IsValid())
259 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid NovaCoin address: ")+s.name_);
261 if (setAddress.count(address))
262 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
263 setAddress.insert(address);
265 CScript scriptPubKey;
266 scriptPubKey.SetDestination(address.Get());
267 int64 nAmount = AmountFromValue(s.value_);
269 CTxOut out(nAmount, scriptPubKey);
270 rawTx.vout.push_back(out);
273 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
275 return HexStr(ss.begin(), ss.end());
278 Value decoderawtransaction(const Array& params, bool fHelp)
280 if (fHelp || params.size() != 1)
282 "decoderawtransaction <hex string>\n"
283 "Return a JSON object representing the serialized, hex-encoded transaction.");
285 RPCTypeCheck(params, list_of(str_type));
287 vector<unsigned char> txData(ParseHex(params[0].get_str()));
288 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
293 catch (std::exception &e) {
294 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
298 TxToJSON(tx, 0, result);
303 Value signrawtransaction(const Array& params, bool fHelp)
305 if (fHelp || params.size() < 1 || params.size() > 4)
307 "signrawtransaction <hex string> [{\"txid\":txid,\"vout\":n,\"scriptPubKey\":hex},...] [<privatekey1>,...] [sighashtype=\"ALL\"]\n"
308 "Sign inputs for raw transaction (serialized, hex-encoded).\n"
309 "Second optional argument (may be null) is an array of previous transaction outputs that\n"
310 "this transaction depends on but may not yet be in the blockchain.\n"
311 "Third optional argument (may be null) is an array of base58-encoded private\n"
312 "keys that, if given, will be the only keys used to sign the transaction.\n"
313 "Fourth optional argument is a string that is one of six values; ALL, NONE, SINGLE or\n"
314 "ALL|ANYONECANPAY, NONE|ANYONECANPAY, SINGLE|ANYONECANPAY.\n"
315 "Returns json object with keys:\n"
316 " hex : raw transaction with signature(s) (hex-encoded string)\n"
317 " complete : 1 if transaction has a complete set of signature (0 if not)"
318 + HelpRequiringPassphrase());
320 RPCTypeCheck(params, list_of(str_type)(array_type)(array_type)(str_type), true);
322 vector<unsigned char> txData(ParseHex(params[0].get_str()));
323 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
324 vector<CTransaction> txVariants;
325 while (!ssData.empty())
330 txVariants.push_back(tx);
332 catch (std::exception &e) {
333 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
337 if (txVariants.empty())
338 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Missing transaction");
340 // mergedTx will end up with all the signatures; it
341 // starts as a clone of the rawtx:
342 CTransaction mergedTx(txVariants[0]);
343 bool fComplete = true;
345 // Fetch previous transactions (inputs):
346 map<COutPoint, CScript> mapPrevOut;
347 for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
352 map<uint256, CTxIndex> unused;
355 // FetchInputs aborts on failure, so we go one at a time.
356 tempTx.vin.push_back(mergedTx.vin[i]);
357 tempTx.FetchInputs(txdb, unused, false, false, mapPrevTx, fInvalid);
359 // Copy results into mapPrevOut:
360 BOOST_FOREACH(const CTxIn& txin, tempTx.vin)
362 const uint256& prevHash = txin.prevout.hash;
363 if (mapPrevTx.count(prevHash) && mapPrevTx[prevHash].second.vout.size()>txin.prevout.n)
364 mapPrevOut[txin.prevout] = mapPrevTx[prevHash].second.vout[txin.prevout.n].scriptPubKey;
368 // Add previous txouts given in the RPC call:
369 if (params.size() > 1 && params[1].type() != null_type)
371 Array prevTxs = params[1].get_array();
372 BOOST_FOREACH(Value& p, prevTxs)
374 if (p.type() != obj_type)
375 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}");
377 Object prevOut = p.get_obj();
379 RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type));
381 string txidHex = find_value(prevOut, "txid").get_str();
383 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "txid must be hexadecimal");
385 txid.SetHex(txidHex);
387 int nOut = find_value(prevOut, "vout").get_int();
389 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive");
391 string pkHex = find_value(prevOut, "scriptPubKey").get_str();
393 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "scriptPubKey must be hexadecimal");
394 vector<unsigned char> pkData(ParseHex(pkHex));
395 CScript scriptPubKey(pkData.begin(), pkData.end());
397 COutPoint outpoint(txid, nOut);
398 if (mapPrevOut.count(outpoint))
400 // Complain if scriptPubKey doesn't match
401 if (mapPrevOut[outpoint] != scriptPubKey)
403 string err("Previous output scriptPubKey mismatch:\n");
404 err = err + mapPrevOut[outpoint].ToString() + "\nvs:\n"+
405 scriptPubKey.ToString();
406 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
410 mapPrevOut[outpoint] = scriptPubKey;
414 bool fGivenKeys = false;
415 CBasicKeyStore tempKeystore;
416 if (params.size() > 2 && params[2].type() != null_type)
419 Array keys = params[2].get_array();
420 BOOST_FOREACH(Value k, keys)
422 CBitcoinSecret vchSecret;
423 bool fGood = vchSecret.SetString(k.get_str());
425 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,"Invalid private key");
428 CSecret secret = vchSecret.GetSecret(fCompressed);
429 key.SetSecret(secret, fCompressed);
430 tempKeystore.AddKey(key);
434 EnsureWalletIsUnlocked();
436 const CKeyStore& keystore = (fGivenKeys ? tempKeystore : *pwalletMain);
438 int nHashType = SIGHASH_ALL;
439 if (params.size() > 3 && params[3].type() != null_type)
441 static map<string, int> mapSigHashValues =
442 boost::assign::map_list_of
443 (string("ALL"), int(SIGHASH_ALL))
444 (string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY))
445 (string("NONE"), int(SIGHASH_NONE))
446 (string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY))
447 (string("SINGLE"), int(SIGHASH_SINGLE))
448 (string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY))
450 string strHashType = params[3].get_str();
451 if (mapSigHashValues.count(strHashType))
452 nHashType = mapSigHashValues[strHashType];
454 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid sighash param");
457 bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
460 for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
462 CTxIn& txin = mergedTx.vin[i];
463 if (mapPrevOut.count(txin.prevout) == 0)
468 const CScript& prevPubKey = mapPrevOut[txin.prevout];
470 txin.scriptSig.clear();
471 // Only sign SIGHASH_SINGLE if there's a corresponding output:
472 if (!fHashSingle || (i < mergedTx.vout.size()))
473 SignSignature(keystore, prevPubKey, mergedTx, i, nHashType);
475 // ... and merge in other signatures:
476 BOOST_FOREACH(const CTransaction& txv, txVariants)
478 txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
480 if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, true, 0))
485 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
487 result.push_back(Pair("hex", HexStr(ssTx.begin(), ssTx.end())));
488 result.push_back(Pair("complete", fComplete));
493 Value sendrawtransaction(const Array& params, bool fHelp)
495 if (fHelp || params.size() < 1 || params.size() > 1)
497 "sendrawtransaction <hex string>\n"
498 "Submits raw transaction (serialized, hex-encoded) to local node and network.");
500 RPCTypeCheck(params, list_of(str_type));
502 // parse hex string from parameter
503 vector<unsigned char> txData(ParseHex(params[0].get_str()));
504 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
507 // deserialize binary data stream
511 catch (std::exception &e) {
512 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
514 uint256 hashTx = tx.GetHash();
516 // See if the transaction is already in a block
517 // or in the memory pool:
518 CTransaction existingTx;
519 uint256 hashBlock = 0;
520 if (GetTransaction(hashTx, existingTx, hashBlock))
523 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("transaction already in block ")+hashBlock.GetHex());
524 // Not in block, but already in the memory pool; will drop
525 // through to re-relay it.
529 // push to local node
531 if (!tx.AcceptToMemoryPool(txdb))
532 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX rejected");
534 SyncWithWallets(tx, NULL, true);
536 RelayMessage(CInv(MSG_TX, hashTx), tx);
538 return hashTx.GetHex();