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, true))
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 CCoinsView viewDummy;
339 CCoinsViewCache view(viewDummy);
342 CCoinsViewCache &viewChain = *pcoinsTip;
343 CCoinsViewMemPool viewMempool(viewChain, mempool);
344 view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view
346 BOOST_FOREACH(const CTxIn& txin, mergedTx.vin) {
347 const uint256& prevHash = txin.prevout.hash;
349 view.GetCoins(prevHash, coins); // this is certainly allowed to fail
352 view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long
355 // Add previous txouts given in the RPC call:
356 if (params.size() > 1 && params[1].type() != null_type)
358 Array prevTxs = params[1].get_array();
359 BOOST_FOREACH(Value& p, prevTxs)
361 if (p.type() != obj_type)
362 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}");
364 Object prevOut = p.get_obj();
366 RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type));
368 string txidHex = find_value(prevOut, "txid").get_str();
370 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "txid must be hexadecimal");
372 txid.SetHex(txidHex);
374 int nOut = find_value(prevOut, "vout").get_int();
376 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive");
378 string pkHex = find_value(prevOut, "scriptPubKey").get_str();
380 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "scriptPubKey must be hexadecimal");
381 vector<unsigned char> pkData(ParseHex(pkHex));
382 CScript scriptPubKey(pkData.begin(), pkData.end());
385 if (view.GetCoins(txid, coins)) {
386 if (coins.IsAvailable(nOut) && coins.vout[nOut].scriptPubKey != scriptPubKey) {
387 string err("Previous output scriptPubKey mismatch:\n");
388 err = err + coins.vout[nOut].scriptPubKey.ToString() + "\nvs:\n"+
389 scriptPubKey.ToString();
390 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
392 // what todo if txid is known, but the actual output isn't?
394 coins.vout[nOut].scriptPubKey = scriptPubKey;
395 coins.vout[nOut].nValue = 0; // we don't know the actual output value
396 view.SetCoins(txid, coins);
400 bool fGivenKeys = false;
401 CBasicKeyStore tempKeystore;
402 if (params.size() > 2 && params[2].type() != null_type)
405 Array keys = params[2].get_array();
406 BOOST_FOREACH(Value k, keys)
408 CBitcoinSecret vchSecret;
409 bool fGood = vchSecret.SetString(k.get_str());
411 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,"Invalid private key");
414 CSecret secret = vchSecret.GetSecret(fCompressed);
415 key.SetSecret(secret, fCompressed);
416 tempKeystore.AddKey(key);
420 EnsureWalletIsUnlocked();
422 const CKeyStore& keystore = (fGivenKeys ? tempKeystore : *pwalletMain);
424 int nHashType = SIGHASH_ALL;
425 if (params.size() > 3 && params[3].type() != null_type)
427 static map<string, int> mapSigHashValues =
428 boost::assign::map_list_of
429 (string("ALL"), int(SIGHASH_ALL))
430 (string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY))
431 (string("NONE"), int(SIGHASH_NONE))
432 (string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY))
433 (string("SINGLE"), int(SIGHASH_SINGLE))
434 (string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY))
436 string strHashType = params[3].get_str();
437 if (mapSigHashValues.count(strHashType))
438 nHashType = mapSigHashValues[strHashType];
440 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid sighash param");
443 bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
446 for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
448 CTxIn& txin = mergedTx.vin[i];
450 if (!view.GetCoins(txin.prevout.hash, coins) || !coins.IsAvailable(txin.prevout.n))
455 const CScript& prevPubKey = coins.vout[txin.prevout.n].scriptPubKey;
457 txin.scriptSig.clear();
458 // Only sign SIGHASH_SINGLE if there's a corresponding output:
459 if (!fHashSingle || (i < mergedTx.vout.size()))
460 SignSignature(keystore, prevPubKey, mergedTx, i, nHashType);
462 // ... and merge in other signatures:
463 BOOST_FOREACH(const CTransaction& txv, txVariants)
465 txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
467 if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, true, true, 0))
472 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
474 result.push_back(Pair("hex", HexStr(ssTx.begin(), ssTx.end())));
475 result.push_back(Pair("complete", fComplete));
480 Value sendrawtransaction(const Array& params, bool fHelp)
482 if (fHelp || params.size() < 1 || params.size() > 1)
484 "sendrawtransaction <hex string>\n"
485 "Submits raw transaction (serialized, hex-encoded) to local node and network.");
487 RPCTypeCheck(params, list_of(str_type));
489 // parse hex string from parameter
490 vector<unsigned char> txData(ParseHex(params[0].get_str()));
491 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
494 // deserialize binary data stream
498 catch (std::exception &e) {
499 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
501 uint256 hashTx = tx.GetHash();
504 CCoinsViewCache &view = *pcoinsTip;
505 CCoins existingCoins;
507 fHave = view.GetCoins(hashTx, existingCoins);
509 // push to local node
510 if (!tx.AcceptToMemoryPool())
511 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX rejected");
515 if (existingCoins.nHeight < 1000000000)
516 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "transaction already in block chain");
517 // Not in block, but already in the memory pool; will drop
518 // through to re-relay it.
520 SyncWithWallets(tx, NULL, true);
522 RelayMessage(CInv(MSG_TX, hashTx), tx);
524 return hashTx.GetHex();