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 entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end())));
198 entry.push_back(Pair("amount",ValueFromAmount(nValue)));
199 entry.push_back(Pair("confirmations",out.nDepth));
200 results.push_back(entry);
206 Value createrawtransaction(const Array& params, bool fHelp)
208 if (fHelp || params.size() != 2)
210 "createrawtransaction [{\"txid\":txid,\"vout\":n},...] {address:amount,...}\n"
211 "Create a transaction spending given inputs\n"
212 "(array of objects containing transaction id and output number),\n"
213 "sending to given address(es).\n"
214 "Returns hex-encoded raw transaction.\n"
215 "Note that the transaction's inputs are not signed, and\n"
216 "it is not stored in the wallet or transmitted to the network.");
218 RPCTypeCheck(params, list_of(array_type)(obj_type));
220 Array inputs = params[0].get_array();
221 Object sendTo = params[1].get_obj();
225 BOOST_FOREACH(Value& input, inputs)
227 const Object& o = input.get_obj();
229 const Value& txid_v = find_value(o, "txid");
230 if (txid_v.type() != str_type)
231 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing txid key");
232 string txid = txid_v.get_str();
234 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
236 const Value& vout_v = find_value(o, "vout");
237 if (vout_v.type() != int_type)
238 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key");
239 int nOutput = vout_v.get_int();
241 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
243 CTxIn in(COutPoint(uint256(txid), nOutput));
244 rawTx.vin.push_back(in);
247 set<CBitcoinAddress> setAddress;
248 BOOST_FOREACH(const Pair& s, sendTo)
250 CBitcoinAddress address(s.name_);
251 if (!address.IsValid())
252 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid NovaCoin address: ")+s.name_);
254 if (setAddress.count(address))
255 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
256 setAddress.insert(address);
258 CScript scriptPubKey;
259 scriptPubKey.SetDestination(address.Get());
260 int64 nAmount = AmountFromValue(s.value_);
262 CTxOut out(nAmount, scriptPubKey);
263 rawTx.vout.push_back(out);
266 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
268 return HexStr(ss.begin(), ss.end());
271 Value decoderawtransaction(const Array& params, bool fHelp)
273 if (fHelp || params.size() != 1)
275 "decoderawtransaction <hex string>\n"
276 "Return a JSON object representing the serialized, hex-encoded transaction.");
278 RPCTypeCheck(params, list_of(str_type));
280 vector<unsigned char> txData(ParseHex(params[0].get_str()));
281 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
286 catch (std::exception &e) {
287 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
291 TxToJSON(tx, 0, result);
296 Value signrawtransaction(const Array& params, bool fHelp)
298 if (fHelp || params.size() < 1 || params.size() > 4)
300 "signrawtransaction <hex string> [{\"txid\":txid,\"vout\":n,\"scriptPubKey\":hex},...] [<privatekey1>,...] [sighashtype=\"ALL\"]\n"
301 "Sign inputs for raw transaction (serialized, hex-encoded).\n"
302 "Second optional argument (may be null) is an array of previous transaction outputs that\n"
303 "this transaction depends on but may not yet be in the blockchain.\n"
304 "Third optional argument (may be null) is an array of base58-encoded private\n"
305 "keys that, if given, will be the only keys used to sign the transaction.\n"
306 "Fourth optional argument is a string that is one of six values; ALL, NONE, SINGLE or\n"
307 "ALL|ANYONECANPAY, NONE|ANYONECANPAY, SINGLE|ANYONECANPAY.\n"
308 "Returns json object with keys:\n"
309 " hex : raw transaction with signature(s) (hex-encoded string)\n"
310 " complete : 1 if transaction has a complete set of signature (0 if not)"
311 + HelpRequiringPassphrase());
313 RPCTypeCheck(params, list_of(str_type)(array_type)(array_type)(str_type), true);
315 vector<unsigned char> txData(ParseHex(params[0].get_str()));
316 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
317 vector<CTransaction> txVariants;
318 while (!ssData.empty())
323 txVariants.push_back(tx);
325 catch (std::exception &e) {
326 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
330 if (txVariants.empty())
331 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Missing transaction");
333 // mergedTx will end up with all the signatures; it
334 // starts as a clone of the rawtx:
335 CTransaction mergedTx(txVariants[0]);
336 bool fComplete = true;
338 // Fetch previous transactions (inputs):
339 map<COutPoint, CScript> mapPrevOut;
340 for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
345 map<uint256, CTxIndex> unused;
348 // FetchInputs aborts on failure, so we go one at a time.
349 tempTx.vin.push_back(mergedTx.vin[i]);
350 tempTx.FetchInputs(txdb, unused, false, false, mapPrevTx, fInvalid);
352 // Copy results into mapPrevOut:
353 BOOST_FOREACH(const CTxIn& txin, tempTx.vin)
355 const uint256& prevHash = txin.prevout.hash;
356 if (mapPrevTx.count(prevHash) && mapPrevTx[prevHash].second.vout.size()>txin.prevout.n)
357 mapPrevOut[txin.prevout] = mapPrevTx[prevHash].second.vout[txin.prevout.n].scriptPubKey;
361 // Add previous txouts given in the RPC call:
362 if (params.size() > 1 && params[1].type() != null_type)
364 Array prevTxs = params[1].get_array();
365 BOOST_FOREACH(Value& p, prevTxs)
367 if (p.type() != obj_type)
368 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}");
370 Object prevOut = p.get_obj();
372 RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type));
374 string txidHex = find_value(prevOut, "txid").get_str();
376 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "txid must be hexadecimal");
378 txid.SetHex(txidHex);
380 int nOut = find_value(prevOut, "vout").get_int();
382 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive");
384 string pkHex = find_value(prevOut, "scriptPubKey").get_str();
386 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "scriptPubKey must be hexadecimal");
387 vector<unsigned char> pkData(ParseHex(pkHex));
388 CScript scriptPubKey(pkData.begin(), pkData.end());
390 COutPoint outpoint(txid, nOut);
391 if (mapPrevOut.count(outpoint))
393 // Complain if scriptPubKey doesn't match
394 if (mapPrevOut[outpoint] != scriptPubKey)
396 string err("Previous output scriptPubKey mismatch:\n");
397 err = err + mapPrevOut[outpoint].ToString() + "\nvs:\n"+
398 scriptPubKey.ToString();
399 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
403 mapPrevOut[outpoint] = scriptPubKey;
407 bool fGivenKeys = false;
408 CBasicKeyStore tempKeystore;
409 if (params.size() > 2 && params[2].type() != null_type)
412 Array keys = params[2].get_array();
413 BOOST_FOREACH(Value k, keys)
415 CBitcoinSecret vchSecret;
416 bool fGood = vchSecret.SetString(k.get_str());
418 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,"Invalid private key");
421 CSecret secret = vchSecret.GetSecret(fCompressed);
422 key.SetSecret(secret, fCompressed);
423 tempKeystore.AddKey(key);
427 EnsureWalletIsUnlocked();
429 const CKeyStore& keystore = (fGivenKeys ? tempKeystore : *pwalletMain);
431 int nHashType = SIGHASH_ALL;
432 if (params.size() > 3 && params[3].type() != null_type)
434 static map<string, int> mapSigHashValues =
435 boost::assign::map_list_of
436 (string("ALL"), int(SIGHASH_ALL))
437 (string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY))
438 (string("NONE"), int(SIGHASH_NONE))
439 (string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY))
440 (string("SINGLE"), int(SIGHASH_SINGLE))
441 (string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY))
443 string strHashType = params[3].get_str();
444 if (mapSigHashValues.count(strHashType))
445 nHashType = mapSigHashValues[strHashType];
447 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid sighash param");
450 bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
453 for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
455 CTxIn& txin = mergedTx.vin[i];
456 if (mapPrevOut.count(txin.prevout) == 0)
461 const CScript& prevPubKey = mapPrevOut[txin.prevout];
463 txin.scriptSig.clear();
464 // Only sign SIGHASH_SINGLE if there's a corresponding output:
465 if (!fHashSingle || (i < mergedTx.vout.size()))
466 SignSignature(keystore, prevPubKey, mergedTx, i, nHashType);
468 // ... and merge in other signatures:
469 BOOST_FOREACH(const CTransaction& txv, txVariants)
471 txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
473 if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, true, 0))
478 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
480 result.push_back(Pair("hex", HexStr(ssTx.begin(), ssTx.end())));
481 result.push_back(Pair("complete", fComplete));
486 Value sendrawtransaction(const Array& params, bool fHelp)
488 if (fHelp || params.size() < 1 || params.size() > 1)
490 "sendrawtransaction <hex string>\n"
491 "Submits raw transaction (serialized, hex-encoded) to local node and network.");
493 RPCTypeCheck(params, list_of(str_type));
495 // parse hex string from parameter
496 vector<unsigned char> txData(ParseHex(params[0].get_str()));
497 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
500 // deserialize binary data stream
504 catch (std::exception &e) {
505 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
507 uint256 hashTx = tx.GetHash();
509 // See if the transaction is already in a block
510 // or in the memory pool:
511 CTransaction existingTx;
512 uint256 hashBlock = 0;
513 if (GetTransaction(hashTx, existingTx, hashBlock))
516 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("transaction already in block ")+hashBlock.GetHex());
517 // Not in block, but already in the memory pool; will drop
518 // through to re-relay it.
522 // push to local node
524 if (!tx.AcceptToMemoryPool(txdb))
525 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX rejected");
527 SyncWithWallets(tx, NULL, true);
529 RelayMessage(CInv(MSG_TX, hashTx), tx);
531 return hashTx.GetHex();