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; // trying to find transaction in the blockchain
124 if (!GetTransaction(hash, tx, hashBlock, true))
126 if (pwalletMain->mapWallet.count(hash))
127 tx = (CTransaction)pwalletMain->mapWallet[hash]; // get transaction from wallet
129 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
132 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
134 string strHex = HexStr(ssTx.begin(), ssTx.end());
140 result.push_back(Pair("hex", strHex));
141 TxToJSON(tx, hashBlock, result);
145 Value listunspent(const Array& params, bool fHelp)
147 if (fHelp || params.size() > 3)
149 "listunspent [minconf=1] [maxconf=9999999] [\"address\",...]\n"
150 "Returns array of unspent transaction outputs\n"
151 "with between minconf and maxconf (inclusive) confirmations.\n"
152 "Optionally filtered to only include txouts paid to specified addresses.\n"
153 "Results are an array of Objects, each of which has:\n"
154 "{txid, vout, scriptPubKey, amount, confirmations}");
156 RPCTypeCheck(params, list_of(int_type)(int_type)(array_type));
159 if (params.size() > 0)
160 nMinDepth = params[0].get_int();
162 int nMaxDepth = 9999999;
163 if (params.size() > 1)
164 nMaxDepth = params[1].get_int();
166 set<CBitcoinAddress> setAddress;
167 if (params.size() > 2)
169 Array inputs = params[2].get_array();
170 BOOST_FOREACH(Value& input, inputs)
172 CBitcoinAddress address(input.get_str());
173 if (!address.IsValid())
174 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid NovaCoin address: ")+input.get_str());
175 if (setAddress.count(address))
176 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str());
177 setAddress.insert(address);
182 vector<COutput> vecOutputs;
183 pwalletMain->AvailableCoins(vecOutputs, false);
184 BOOST_FOREACH(const COutput& out, vecOutputs)
186 if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
189 if(setAddress.size())
191 CTxDestination address;
192 if(!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
195 if (!setAddress.count(address))
199 int64 nValue = out.tx->vout[out.i].nValue;
200 const CScript& pk = out.tx->vout[out.i].scriptPubKey;
202 entry.push_back(Pair("txid", out.tx->GetHash().GetHex()));
203 entry.push_back(Pair("vout", out.i));
204 CTxDestination address;
205 if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
207 entry.push_back(Pair("address", CBitcoinAddress(address).ToString()));
208 if (pwalletMain->mapAddressBook.count(address))
209 entry.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
211 entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end())));
212 entry.push_back(Pair("amount",ValueFromAmount(nValue)));
213 entry.push_back(Pair("confirmations",out.nDepth));
214 results.push_back(entry);
220 Value decodescript(const Array& params, bool fHelp)
222 if (fHelp || params.size() != 1)
224 "decodescript <hex string>\n"
225 "Decode a hex-encoded script.");
227 RPCTypeCheck(params, list_of(str_type));
231 if (params[0].get_str().size() > 0){
232 vector<unsigned char> scriptData(ParseHexV(params[0], "argument"));
233 script = CScript(scriptData.begin(), scriptData.end());
235 // Empty scripts are valid
237 ScriptPubKeyToJSON(script, r, false);
239 r.push_back(Pair("p2sh", CBitcoinAddress(script.GetID()).ToString()));
243 Value createrawtransaction(const Array& params, bool fHelp)
245 if (fHelp || params.size() != 2)
247 "createrawtransaction [{\"txid\":txid,\"vout\":n},...] {address:amount,...}\n"
248 "Create a transaction spending given inputs\n"
249 "(array of objects containing transaction id and output number),\n"
250 "sending to given address(es).\n"
251 "Returns hex-encoded raw transaction.\n"
252 "Note that the transaction's inputs are not signed, and\n"
253 "it is not stored in the wallet or transmitted to the network.");
255 RPCTypeCheck(params, list_of(array_type)(obj_type));
257 Array inputs = params[0].get_array();
258 Object sendTo = params[1].get_obj();
262 BOOST_FOREACH(Value& input, inputs)
264 const Object& o = input.get_obj();
266 const Value& txid_v = find_value(o, "txid");
267 if (txid_v.type() != str_type)
268 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing txid key");
269 string txid = txid_v.get_str();
271 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
273 const Value& vout_v = find_value(o, "vout");
274 if (vout_v.type() != int_type)
275 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key");
276 int nOutput = vout_v.get_int();
278 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
280 CTxIn in(COutPoint(uint256(txid), nOutput));
281 rawTx.vin.push_back(in);
284 set<CBitcoinAddress> setAddress;
285 BOOST_FOREACH(const Pair& s, sendTo)
287 CBitcoinAddress address(s.name_);
288 if (!address.IsValid())
289 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+s.name_);
291 if (setAddress.count(address))
292 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
293 setAddress.insert(address);
295 CScript scriptPubKey;
296 scriptPubKey.SetDestination(address.Get());
297 int64 nAmount = AmountFromValue(s.value_);
299 CTxOut out(nAmount, scriptPubKey);
300 rawTx.vout.push_back(out);
303 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
305 return HexStr(ss.begin(), ss.end());
308 Value decoderawtransaction(const Array& params, bool fHelp)
310 if (fHelp || params.size() != 1)
312 "decoderawtransaction <hex string>\n"
313 "Return a JSON object representing the serialized, hex-encoded transaction.");
315 RPCTypeCheck(params, list_of(str_type));
317 vector<unsigned char> txData(ParseHex(params[0].get_str()));
318 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
323 catch (std::exception &e) {
324 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
328 TxToJSON(tx, 0, result);
333 Value signrawtransaction(const Array& params, bool fHelp)
335 if (fHelp || params.size() < 1 || params.size() > 4)
337 "signrawtransaction <hex string> [{\"txid\":txid,\"vout\":n,\"scriptPubKey\":hex},...] [<privatekey1>,...] [sighashtype=\"ALL\"]\n"
338 "Sign inputs for raw transaction (serialized, hex-encoded).\n"
339 "Second optional argument (may be null) is an array of previous transaction outputs that\n"
340 "this transaction depends on but may not yet be in the blockchain.\n"
341 "Third optional argument (may be null) is an array of base58-encoded private\n"
342 "keys that, if given, will be the only keys used to sign the transaction.\n"
343 "Fourth optional argument is a string that is one of six values; ALL, NONE, SINGLE or\n"
344 "ALL|ANYONECANPAY, NONE|ANYONECANPAY, SINGLE|ANYONECANPAY.\n"
345 "Returns json object with keys:\n"
346 " hex : raw transaction with signature(s) (hex-encoded string)\n"
347 " complete : 1 if transaction has a complete set of signature (0 if not)"
348 + HelpRequiringPassphrase());
350 RPCTypeCheck(params, list_of(str_type)(array_type)(array_type)(str_type), true);
352 vector<unsigned char> txData(ParseHex(params[0].get_str()));
353 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
354 vector<CTransaction> txVariants;
355 while (!ssData.empty())
360 txVariants.push_back(tx);
362 catch (std::exception &e) {
363 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
367 if (txVariants.empty())
368 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Missing transaction");
370 // mergedTx will end up with all the signatures; it
371 // starts as a clone of the rawtx:
372 CTransaction mergedTx(txVariants[0]);
373 bool fComplete = true;
375 // Fetch previous transactions (inputs):
376 CCoinsView viewDummy;
377 CCoinsViewCache view(viewDummy);
380 CCoinsViewCache &viewChain = *pcoinsTip;
381 CCoinsViewMemPool viewMempool(viewChain, mempool);
382 view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view
384 BOOST_FOREACH(const CTxIn& txin, mergedTx.vin) {
385 const uint256& prevHash = txin.prevout.hash;
387 view.GetCoins(prevHash, coins); // this is certainly allowed to fail
390 view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long
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());
423 if (view.GetCoins(txid, coins)) {
424 if (coins.IsAvailable(nOut) && coins.vout[nOut].scriptPubKey != scriptPubKey) {
425 string err("Previous output scriptPubKey mismatch:\n");
426 err = err + coins.vout[nOut].scriptPubKey.ToString() + "\nvs:\n"+
427 scriptPubKey.ToString();
428 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
430 // what todo if txid is known, but the actual output isn't?
432 coins.vout[nOut].scriptPubKey = scriptPubKey;
433 coins.vout[nOut].nValue = 0; // we don't know the actual output value
434 view.SetCoins(txid, coins);
438 bool fGivenKeys = false;
439 CBasicKeyStore tempKeystore;
440 if (params.size() > 2 && params[2].type() != null_type)
443 Array keys = params[2].get_array();
444 BOOST_FOREACH(Value k, keys)
446 CBitcoinSecret vchSecret;
447 bool fGood = vchSecret.SetString(k.get_str());
449 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,"Invalid private key");
452 CSecret secret = vchSecret.GetSecret(fCompressed);
453 key.SetSecret(secret, fCompressed);
454 tempKeystore.AddKey(key);
458 EnsureWalletIsUnlocked();
460 const CKeyStore& keystore = (fGivenKeys ? tempKeystore : *pwalletMain);
462 int nHashType = SIGHASH_ALL;
463 if (params.size() > 3 && params[3].type() != null_type)
465 static map<string, int> mapSigHashValues =
466 boost::assign::map_list_of
467 (string("ALL"), int(SIGHASH_ALL))
468 (string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY))
469 (string("NONE"), int(SIGHASH_NONE))
470 (string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY))
471 (string("SINGLE"), int(SIGHASH_SINGLE))
472 (string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY))
474 string strHashType = params[3].get_str();
475 if (mapSigHashValues.count(strHashType))
476 nHashType = mapSigHashValues[strHashType];
478 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid sighash param");
481 bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
484 for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
486 CTxIn& txin = mergedTx.vin[i];
488 if (!view.GetCoins(txin.prevout.hash, coins) || !coins.IsAvailable(txin.prevout.n))
493 const CScript& prevPubKey = coins.vout[txin.prevout.n].scriptPubKey;
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, 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();
542 CCoinsViewCache &view = *pcoinsTip;
543 CCoins existingCoins;
545 fHave = view.GetCoins(hashTx, existingCoins);
547 // push to local node
548 if (!tx.AcceptToMemoryPool())
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(hashTx, tx, NULL, true);
560 RelayTransaction(tx, hashTx);
562 return hashTx.GetHex();