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("locktime", (boost::int64_t)tx.nLockTime));
51 BOOST_FOREACH(const CTxIn& txin, tx.vin)
55 in.push_back(Pair("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
58 in.push_back(Pair("txid", txin.prevout.hash.GetHex()));
59 in.push_back(Pair("vout", (boost::int64_t)txin.prevout.n));
61 o.push_back(Pair("asm", txin.scriptSig.ToString()));
62 o.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
63 in.push_back(Pair("scriptSig", o));
65 in.push_back(Pair("sequence", (boost::int64_t)txin.nSequence));
68 entry.push_back(Pair("vin", vin));
70 for (unsigned int i = 0; i < tx.vout.size(); i++)
72 const CTxOut& txout = tx.vout[i];
74 out.push_back(Pair("value", ValueFromAmount(txout.nValue)));
75 out.push_back(Pair("n", (boost::int64_t)i));
77 ScriptPubKeyToJSON(txout.scriptPubKey, o);
78 out.push_back(Pair("scriptPubKey", o));
81 entry.push_back(Pair("vout", vout));
85 entry.push_back(Pair("blockhash", hashBlock.GetHex()));
86 map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
87 if (mi != mapBlockIndex.end() && (*mi).second)
89 CBlockIndex* pindex = (*mi).second;
90 if (pindex->IsInMainChain())
92 entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight));
93 entry.push_back(Pair("time", (boost::int64_t)pindex->nTime));
94 entry.push_back(Pair("blocktime", (boost::int64_t)pindex->nTime));
97 entry.push_back(Pair("confirmations", 0));
102 Value getrawtransaction(const Array& params, bool fHelp)
104 if (fHelp || params.size() < 1 || params.size() > 2)
106 "getrawtransaction <txid> [verbose=0]\n"
107 "If verbose=0, returns a string that is\n"
108 "serialized, hex-encoded data for <txid>.\n"
109 "If verbose is non-zero, returns an Object\n"
110 "with information about <txid>.");
113 hash.SetHex(params[0].get_str());
115 bool fVerbose = false;
116 if (params.size() > 1)
117 fVerbose = (params[1].get_int() != 0);
120 uint256 hashBlock = 0;
121 if (!GetTransaction(hash, tx, hashBlock))
122 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
124 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
126 string strHex = HexStr(ssTx.begin(), ssTx.end());
132 result.push_back(Pair("hex", strHex));
133 TxToJSON(tx, hashBlock, result);
137 Value listunspent(const Array& params, bool fHelp)
139 if (fHelp || params.size() > 3)
141 "listunspent [minconf=1] [maxconf=9999999] [\"address\",...]\n"
142 "Returns array of unspent transaction outputs\n"
143 "with between minconf and maxconf (inclusive) confirmations.\n"
144 "Optionally filtered to only include txouts paid to specified addresses.\n"
145 "Results are an array of Objects, each of which has:\n"
146 "{txid, vout, scriptPubKey, amount, confirmations}");
148 RPCTypeCheck(params, list_of(int_type)(int_type)(array_type));
151 if (params.size() > 0)
152 nMinDepth = params[0].get_int();
154 int nMaxDepth = 9999999;
155 if (params.size() > 1)
156 nMaxDepth = params[1].get_int();
158 set<CBitcoinAddress> setAddress;
159 if (params.size() > 2)
161 Array inputs = params[2].get_array();
162 BOOST_FOREACH(Value& input, inputs)
164 CBitcoinAddress address(input.get_str());
165 if (!address.IsValid())
166 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+input.get_str());
167 if (setAddress.count(address))
168 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str());
169 setAddress.insert(address);
174 vector<COutput> vecOutputs;
175 pwalletMain->AvailableCoins(vecOutputs, false);
176 BOOST_FOREACH(const COutput& out, vecOutputs)
178 if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
181 if(setAddress.size())
183 CTxDestination address;
184 if(!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
187 if (!setAddress.count(address))
191 int64 nValue = out.tx->vout[out.i].nValue;
192 const CScript& pk = out.tx->vout[out.i].scriptPubKey;
194 entry.push_back(Pair("txid", out.tx->GetHash().GetHex()));
195 entry.push_back(Pair("vout", out.i));
196 entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end())));
197 entry.push_back(Pair("amount",ValueFromAmount(nValue)));
198 entry.push_back(Pair("confirmations",out.nDepth));
199 results.push_back(entry);
205 Value createrawtransaction(const Array& params, bool fHelp)
207 if (fHelp || params.size() != 2)
209 "createrawtransaction [{\"txid\":txid,\"vout\":n},...] {address:amount,...}\n"
210 "Create a transaction spending given inputs\n"
211 "(array of objects containing transaction id and output number),\n"
212 "sending to given address(es).\n"
213 "Returns hex-encoded raw transaction.\n"
214 "Note that the transaction's inputs are not signed, and\n"
215 "it is not stored in the wallet or transmitted to the network.");
217 RPCTypeCheck(params, list_of(array_type)(obj_type));
219 Array inputs = params[0].get_array();
220 Object sendTo = params[1].get_obj();
224 BOOST_FOREACH(Value& input, inputs)
226 const Object& o = input.get_obj();
228 const Value& txid_v = find_value(o, "txid");
229 if (txid_v.type() != str_type)
230 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing txid key");
231 string txid = txid_v.get_str();
233 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
235 const Value& vout_v = find_value(o, "vout");
236 if (vout_v.type() != int_type)
237 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key");
238 int nOutput = vout_v.get_int();
240 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
242 CTxIn in(COutPoint(uint256(txid), nOutput));
243 rawTx.vin.push_back(in);
246 set<CBitcoinAddress> setAddress;
247 BOOST_FOREACH(const Pair& s, sendTo)
249 CBitcoinAddress address(s.name_);
250 if (!address.IsValid())
251 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+s.name_);
253 if (setAddress.count(address))
254 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
255 setAddress.insert(address);
257 CScript scriptPubKey;
258 scriptPubKey.SetDestination(address.Get());
259 int64 nAmount = AmountFromValue(s.value_);
261 CTxOut out(nAmount, scriptPubKey);
262 rawTx.vout.push_back(out);
265 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
267 return HexStr(ss.begin(), ss.end());
270 Value decoderawtransaction(const Array& params, bool fHelp)
272 if (fHelp || params.size() != 1)
274 "decoderawtransaction <hex string>\n"
275 "Return a JSON object representing the serialized, hex-encoded transaction.");
277 RPCTypeCheck(params, list_of(str_type));
279 vector<unsigned char> txData(ParseHex(params[0].get_str()));
280 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
285 catch (std::exception &e) {
286 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
290 TxToJSON(tx, 0, result);
295 Value signrawtransaction(const Array& params, bool fHelp)
297 if (fHelp || params.size() < 1 || params.size() > 4)
299 "signrawtransaction <hex string> [{\"txid\":txid,\"vout\":n,\"scriptPubKey\":hex},...] [<privatekey1>,...] [sighashtype=\"ALL\"]\n"
300 "Sign inputs for raw transaction (serialized, hex-encoded).\n"
301 "Second optional argument (may be null) is an array of previous transaction outputs that\n"
302 "this transaction depends on but may not yet be in the blockchain.\n"
303 "Third optional argument (may be null) is an array of base58-encoded private\n"
304 "keys that, if given, will be the only keys used to sign the transaction.\n"
305 "Fourth optional argument is a string that is one of six values; ALL, NONE, SINGLE or\n"
306 "ALL|ANYONECANPAY, NONE|ANYONECANPAY, SINGLE|ANYONECANPAY.\n"
307 "Returns json object with keys:\n"
308 " hex : raw transaction with signature(s) (hex-encoded string)\n"
309 " complete : 1 if transaction has a complete set of signature (0 if not)"
310 + HelpRequiringPassphrase());
312 RPCTypeCheck(params, list_of(str_type)(array_type)(array_type)(str_type), true);
314 vector<unsigned char> txData(ParseHex(params[0].get_str()));
315 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
316 vector<CTransaction> txVariants;
317 while (!ssData.empty())
322 txVariants.push_back(tx);
324 catch (std::exception &e) {
325 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
329 if (txVariants.empty())
330 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Missing transaction");
332 // mergedTx will end up with all the signatures; it
333 // starts as a clone of the rawtx:
334 CTransaction mergedTx(txVariants[0]);
335 bool fComplete = true;
337 // Fetch previous transactions (inputs):
338 map<COutPoint, CScript> mapPrevOut;
339 for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
344 map<uint256, CTxIndex> unused;
347 // FetchInputs aborts on failure, so we go one at a time.
348 tempTx.vin.push_back(mergedTx.vin[i]);
349 tempTx.FetchInputs(txdb, unused, false, false, mapPrevTx, fInvalid);
351 // Copy results into mapPrevOut:
352 BOOST_FOREACH(const CTxIn& txin, tempTx.vin)
354 const uint256& prevHash = txin.prevout.hash;
355 if (mapPrevTx.count(prevHash) && mapPrevTx[prevHash].second.vout.size()>txin.prevout.n)
356 mapPrevOut[txin.prevout] = mapPrevTx[prevHash].second.vout[txin.prevout.n].scriptPubKey;
360 // Add previous txouts given in the RPC call:
361 if (params.size() > 1 && params[1].type() != null_type)
363 Array prevTxs = params[1].get_array();
364 BOOST_FOREACH(Value& p, prevTxs)
366 if (p.type() != obj_type)
367 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}");
369 Object prevOut = p.get_obj();
371 RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type));
373 string txidHex = find_value(prevOut, "txid").get_str();
375 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "txid must be hexadecimal");
377 txid.SetHex(txidHex);
379 int nOut = find_value(prevOut, "vout").get_int();
381 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive");
383 string pkHex = find_value(prevOut, "scriptPubKey").get_str();
385 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "scriptPubKey must be hexadecimal");
386 vector<unsigned char> pkData(ParseHex(pkHex));
387 CScript scriptPubKey(pkData.begin(), pkData.end());
389 COutPoint outpoint(txid, nOut);
390 if (mapPrevOut.count(outpoint))
392 // Complain if scriptPubKey doesn't match
393 if (mapPrevOut[outpoint] != scriptPubKey)
395 string err("Previous output scriptPubKey mismatch:\n");
396 err = err + mapPrevOut[outpoint].ToString() + "\nvs:\n"+
397 scriptPubKey.ToString();
398 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
402 mapPrevOut[outpoint] = scriptPubKey;
406 bool fGivenKeys = false;
407 CBasicKeyStore tempKeystore;
408 if (params.size() > 2 && params[2].type() != null_type)
411 Array keys = params[2].get_array();
412 BOOST_FOREACH(Value k, keys)
414 CBitcoinSecret vchSecret;
415 bool fGood = vchSecret.SetString(k.get_str());
417 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,"Invalid private key");
420 CSecret secret = vchSecret.GetSecret(fCompressed);
421 key.SetSecret(secret, fCompressed);
422 tempKeystore.AddKey(key);
426 EnsureWalletIsUnlocked();
428 const CKeyStore& keystore = (fGivenKeys ? tempKeystore : *pwalletMain);
430 int nHashType = SIGHASH_ALL;
431 if (params.size() > 3 && params[3].type() != null_type)
433 static map<string, int> mapSigHashValues =
434 boost::assign::map_list_of
435 (string("ALL"), int(SIGHASH_ALL))
436 (string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY))
437 (string("NONE"), int(SIGHASH_NONE))
438 (string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY))
439 (string("SINGLE"), int(SIGHASH_SINGLE))
440 (string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY))
442 string strHashType = params[3].get_str();
443 if (mapSigHashValues.count(strHashType))
444 nHashType = mapSigHashValues[strHashType];
446 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid sighash param");
449 bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
452 for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
454 CTxIn& txin = mergedTx.vin[i];
455 if (mapPrevOut.count(txin.prevout) == 0)
460 const CScript& prevPubKey = mapPrevOut[txin.prevout];
462 txin.scriptSig.clear();
463 // Only sign SIGHASH_SINGLE if there's a corresponding output:
464 if (!fHashSingle || (i < mergedTx.vout.size()))
465 SignSignature(keystore, prevPubKey, mergedTx, i, nHashType);
467 // ... and merge in other signatures:
468 BOOST_FOREACH(const CTransaction& txv, txVariants)
470 txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
472 if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, true, 0))
477 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
479 result.push_back(Pair("hex", HexStr(ssTx.begin(), ssTx.end())));
480 result.push_back(Pair("complete", fComplete));
485 Value sendrawtransaction(const Array& params, bool fHelp)
487 if (fHelp || params.size() < 1 || params.size() > 1)
489 "sendrawtransaction <hex string>\n"
490 "Submits raw transaction (serialized, hex-encoded) to local node and network.");
492 RPCTypeCheck(params, list_of(str_type));
494 // parse hex string from parameter
495 vector<unsigned char> txData(ParseHex(params[0].get_str()));
496 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
499 // deserialize binary data stream
503 catch (std::exception &e) {
504 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
506 uint256 hashTx = tx.GetHash();
508 // See if the transaction is already in a block
509 // or in the memory pool:
510 CTransaction existingTx;
511 uint256 hashBlock = 0;
512 if (GetTransaction(hashTx, existingTx, hashBlock))
515 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("transaction already in block ")+hashBlock.GetHex());
516 // Not in block, but already in the memory pool; will drop
517 // through to re-relay it.
521 // push to local node
523 if (!tx.AcceptToMemoryPool(txdb))
524 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX rejected");
526 SyncWithWallets(tx, NULL, true);
528 RelayMessage(CInv(MSG_TX, hashTx), tx);
530 return hashTx.GetHex();