Get rid of boost::split function
[novacoin.git] / src / rpcrawtransaction.cpp
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.
5
6 #include <boost/assign/list_of.hpp>
7
8 #include "base58.h"
9 #include "bitcoinrpc.h"
10 #include "txdb.h"
11 #include "init.h"
12 #include "main.h"
13 #include "net.h"
14 #include "wallet.h"
15
16 using namespace std;
17 using namespace boost;
18 using namespace boost::assign;
19 using namespace json_spirit;
20
21 void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeHex)
22 {
23     txnouttype type;
24     vector<CTxDestination> addresses;
25     int nRequired;
26
27     out.push_back(Pair("asm", scriptPubKey.ToString()));
28
29     if (fIncludeHex)
30         out.push_back(Pair("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end())));
31
32     if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired))
33     {
34         out.push_back(Pair("type", GetTxnOutputType(TX_NONSTANDARD)));
35         return;
36     }
37
38     if (type != TX_NULL_DATA)
39     {
40         out.push_back(Pair("reqSigs", nRequired));
41         out.push_back(Pair("type", GetTxnOutputType(type)));
42
43         if (type == TX_PUBKEY_DROP)
44         {
45             vector<valtype> vSolutions;
46             Solver(scriptPubKey, type, vSolutions);
47             out.push_back(Pair("keyVariant", HexStr(vSolutions[0])));
48             out.push_back(Pair("R", HexStr(vSolutions[1])));
49
50             CMalleableKeyView view;
51             if (pwalletMain->CheckOwnership(CPubKey(vSolutions[0]), CPubKey(vSolutions[1]), view))
52                 out.push_back(Pair("pubkeyPair", CBitcoinAddress(view.GetMalleablePubKey()).ToString()));
53         }
54         else
55         {
56             Array a;
57             BOOST_FOREACH(const CTxDestination& addr, addresses)
58                 a.push_back(CBitcoinAddress(addr).ToString());
59             out.push_back(Pair("addresses", a));
60         }
61     }
62     else
63     {
64         out.push_back(Pair("type", GetTxnOutputType(type)));
65     }
66 }
67
68 void TxToJSON(const CTransaction& tx, const uint256& hashBlock, Object& entry)
69 {
70     entry.push_back(Pair("txid", tx.GetHash().GetHex()));
71     entry.push_back(Pair("version", tx.nVersion));
72     entry.push_back(Pair("time", (int64_t)tx.nTime));
73     entry.push_back(Pair("locktime", (int64_t)tx.nLockTime));
74     Array vin;
75     BOOST_FOREACH(const CTxIn& txin, tx.vin)
76     {
77         Object in;
78         if (tx.IsCoinBase())
79             in.push_back(Pair("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
80         else
81         {
82             in.push_back(Pair("txid", txin.prevout.hash.GetHex()));
83             in.push_back(Pair("vout", (int64_t)txin.prevout.n));
84             Object o;
85             o.push_back(Pair("asm", txin.scriptSig.ToString()));
86             o.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
87             in.push_back(Pair("scriptSig", o));
88         }
89         in.push_back(Pair("sequence", (int64_t)txin.nSequence));
90         vin.push_back(in);
91     }
92     entry.push_back(Pair("vin", vin));
93     Array vout;
94     for (unsigned int i = 0; i < tx.vout.size(); i++)
95     {
96         const CTxOut& txout = tx.vout[i];
97         Object out;
98         out.push_back(Pair("value", ValueFromAmount(txout.nValue)));
99         out.push_back(Pair("n", (int64_t)i));
100         Object o;
101         ScriptPubKeyToJSON(txout.scriptPubKey, o, true);
102         out.push_back(Pair("scriptPubKey", o));
103         vout.push_back(out);
104     }
105     entry.push_back(Pair("vout", vout));
106
107     if (hashBlock != 0)
108     {
109         entry.push_back(Pair("blockhash", hashBlock.GetHex()));
110         map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
111         if (mi != mapBlockIndex.end() && (*mi).second)
112         {
113             CBlockIndex* pindex = (*mi).second;
114             if (pindex->IsInMainChain())
115             {
116                 entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight));
117                 entry.push_back(Pair("time", (int64_t)pindex->nTime));
118                 entry.push_back(Pair("blocktime", (int64_t)pindex->nTime));
119             }
120             else
121                 entry.push_back(Pair("confirmations", 0));
122         }
123     }
124 }
125
126 Value getrawtransaction(const Array& params, bool fHelp)
127 {
128     if (fHelp || params.size() < 1 || params.size() > 2)
129         throw runtime_error(
130             "getrawtransaction <txid> [verbose=0]\n"
131             "If verbose=0, returns a string that is\n"
132             "serialized, hex-encoded data for <txid>.\n"
133             "If verbose is non-zero, returns an Object\n"
134             "with information about <txid>.");
135
136     uint256 hash;
137     hash.SetHex(params[0].get_str());
138
139     bool fVerbose = false;
140     if (params.size() > 1)
141         fVerbose = (params[1].get_int() != 0);
142
143     CTransaction tx;
144     uint256 hashBlock = 0;
145     if (!GetTransaction(hash, tx, hashBlock))
146         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
147
148     CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
149     ssTx << tx;
150     string strHex = HexStr(ssTx.begin(), ssTx.end());
151
152     if (!fVerbose)
153         return strHex;
154
155     Object result;
156     result.push_back(Pair("hex", strHex));
157     TxToJSON(tx, hashBlock, result);
158     return result;
159 }
160
161 Value listunspent(const Array& params, bool fHelp)
162 {
163     if (fHelp || params.size() > 3)
164         throw runtime_error(
165             "listunspent [minconf=1] [maxconf=9999999]  [\"address\",...]\n"
166             "Returns array of unspent transaction outputs\n"
167             "with between minconf and maxconf (inclusive) confirmations.\n"
168             "Optionally filtered to only include txouts paid to specified addresses.\n"
169             "Results are an array of Objects, each of which has:\n"
170             "{txid, vout, scriptPubKey, amount, confirmations}");
171
172     RPCTypeCheck(params, list_of(int_type)(int_type)(array_type));
173
174     int nMinDepth = 1;
175     if (params.size() > 0)
176         nMinDepth = params[0].get_int();
177
178     int nMaxDepth = 9999999;
179     if (params.size() > 1)
180         nMaxDepth = params[1].get_int();
181
182     set<CBitcoinAddress> setAddress;
183     if (params.size() > 2)
184     {
185         Array inputs = params[2].get_array();
186         BOOST_FOREACH(Value& input, inputs)
187         {
188             CBitcoinAddress address(input.get_str());
189             if (!address.IsValid())
190                 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid NovaCoin address: ")+input.get_str());
191             if (setAddress.count(address))
192                 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str());
193            setAddress.insert(address);
194         }
195     }
196
197     Array results;
198     vector<COutput> vecOutputs;
199     pwalletMain->AvailableCoins(vecOutputs, false);
200     BOOST_FOREACH(const COutput& out, vecOutputs)
201     {
202         if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
203             continue;
204
205         if(setAddress.size())
206         {
207             CTxDestination address;
208             if(!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
209                 continue;
210
211             if (!setAddress.count(address))
212                 continue;
213         }
214
215         int64_t nValue = out.tx->vout[out.i].nValue;
216         const CScript& pk = out.tx->vout[out.i].scriptPubKey;
217         Object entry;
218         entry.push_back(Pair("txid", out.tx->GetHash().GetHex()));
219         entry.push_back(Pair("vout", out.i));
220         CTxDestination address;
221         if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
222         {
223             entry.push_back(Pair("address", CBitcoinAddress(address).ToString()));
224             if (pwalletMain->mapAddressBook.count(address))
225                 entry.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
226         }
227         entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end())));
228         if (pk.IsPayToScriptHash())
229         {
230             CTxDestination address;
231             if (ExtractDestination(pk, address))
232             {
233                 const CScriptID& hash = boost::get<CScriptID>(address);
234                 CScript redeemScript;
235                 if (pwalletMain->GetCScript(hash, redeemScript))
236                     entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end())));
237             }
238         }
239         entry.push_back(Pair("amount",ValueFromAmount(nValue)));
240         entry.push_back(Pair("confirmations",out.nDepth));
241         entry.push_back(Pair("spendable", out.fSpendable));
242         results.push_back(entry);
243     }
244
245     return results;
246 }
247
248 Value createrawtransaction(const Array& params, bool fHelp)
249 {
250     if (fHelp || params.size() > 3 || params.size() < 2)
251         throw runtime_error(
252             "createrawtransaction <'[{\"txid\":txid,\"vout\":n},...]'> <'{address:amount,...}'> [hex data]\n"
253             "Create a transaction spending given inputs\n"
254             "(array of objects containing transaction id and output number),\n"
255             "sending to given address(es),\n"
256             "optional data to add into data-carrying output.\n"
257             "Returns hex-encoded raw transaction.\n"
258             "Note that the transaction's inputs are not signed, and\n"
259             "it is not stored in the wallet or transmitted to the network.");
260
261     RPCTypeCheck(params, list_of(array_type)(obj_type));
262
263     Array inputs = params[0].get_array();
264     Object sendTo = params[1].get_obj();
265
266     CTransaction rawTx;
267
268     BOOST_FOREACH(Value& input, inputs)
269     {
270         const Object& o = input.get_obj();
271
272         const Value& txid_v = find_value(o, "txid");
273         if (txid_v.type() != str_type)
274             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing txid key");
275         string txid = txid_v.get_str();
276         if (!IsHex(txid))
277             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
278
279         const Value& vout_v = find_value(o, "vout");
280         if (vout_v.type() != int_type)
281             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key");
282         int nOutput = vout_v.get_int();
283         if (nOutput < 0)
284             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
285
286         CTxIn in(COutPoint(uint256(txid), nOutput));
287         rawTx.vin.push_back(in);
288     }
289
290     set<CBitcoinAddress> setAddress;
291     BOOST_FOREACH(const Pair& s, sendTo)
292     {
293         // Create output destination script
294         CScript scriptPubKey;
295         CBitcoinAddress address(s.name_);
296
297         if (address.IsValid())
298         {
299             if (!address.IsPair())
300             {
301                 scriptPubKey.SetDestination(address.Get());
302                 if (setAddress.count(address))
303                     throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
304                 setAddress.insert(address);
305             }
306             else
307             {
308                 CMalleablePubKey mpk;
309                 if (!mpk.setvch(address.GetData()))
310                     throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid output destination: ")+s.name_);
311
312                 CPubKey R, pubKeyVariant;
313                 mpk.GetVariant(R, pubKeyVariant);
314                 scriptPubKey.SetDestination(R, pubKeyVariant);
315             }
316         }
317         else
318             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid output destination: ")+s.name_);
319
320         int64_t nAmount = AmountFromValue(s.value_);
321
322         CTxOut out(nAmount, scriptPubKey);
323         rawTx.vout.push_back(out);
324     }
325
326     if (params.size() == 3)
327     {
328         // Data carrying output
329         CScript scriptPubKey;
330         scriptPubKey << OP_RETURN << ParseHex(params[2].get_str());
331         CTxOut out(0, scriptPubKey);
332         rawTx.vout.push_back(out);
333     }
334
335     CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
336     ss << rawTx;
337     return HexStr(ss.begin(), ss.end());
338 }
339
340 Value decoderawtransaction(const Array& params, bool fHelp)
341 {
342     if (fHelp || params.size() != 1)
343         throw runtime_error(
344             "decoderawtransaction <hex string>\n"
345             "Return a JSON object representing the serialized, hex-encoded transaction.");
346
347     RPCTypeCheck(params, list_of(str_type));
348
349     vector<unsigned char> txData(ParseHex(params[0].get_str()));
350     CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
351     CTransaction tx;
352     try {
353         ssData >> tx;
354     }
355     catch (const std::exception&) {
356         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
357     }
358
359     Object result;
360     TxToJSON(tx, 0, result);
361
362     return result;
363 }
364
365 Value decodescript(const Array& params, bool fHelp)
366 {
367     if (fHelp || params.size() != 1)
368         throw runtime_error(
369             "decodescript <hex string>\n"
370             "Decode a hex-encoded script.");
371
372     RPCTypeCheck(params, list_of(str_type));
373
374     Object r;
375     CScript script;
376     if (params[0].get_str().size() > 0){
377         vector<unsigned char> scriptData(ParseHexV(params[0], "argument"));
378         script = CScript(scriptData.begin(), scriptData.end());
379     } else {
380         // Empty scripts are valid
381     }
382     ScriptPubKeyToJSON(script, r, false);
383
384     r.push_back(Pair("p2sh", CBitcoinAddress(script.GetID()).ToString()));
385     return r;
386 }
387
388 Value signrawtransaction(const Array& params, bool fHelp)
389 {
390     if (fHelp || params.size() < 1 || params.size() > 4)
391         throw runtime_error(
392             "signrawtransaction <hex string> '[{\"txid\":txid,\"vout\":n,\"scriptPubKey\":hex,\"redeemScript\":hex},...]' '[<privatekey1>,...]' [sighashtype=\"ALL\"]\n"
393             "Sign inputs for raw transaction (serialized, hex-encoded).\n"
394             "Second optional argument (may be null) is an array of previous transaction outputs that\n"
395             "this transaction depends on but may not yet be in the blockchain.\n"
396             "Third optional argument (may be null) is an array of base58-encoded private\n"
397             "keys that, if given, will be the only keys used to sign the transaction.\n"
398             "Fourth optional argument is a string that is one of six values; ALL, NONE, SINGLE or\n"
399             "ALL|ANYONECANPAY, NONE|ANYONECANPAY, SINGLE|ANYONECANPAY.\n"
400             "Returns json object with keys:\n"
401             "  hex : raw transaction with signature(s) (hex-encoded string)\n"
402             "  complete : 1 if transaction has a complete set of signature (0 if not)"
403             + HelpRequiringPassphrase());
404
405     RPCTypeCheck(params, list_of(str_type)(array_type)(array_type)(str_type), true);
406
407     vector<unsigned char> txData(ParseHex(params[0].get_str()));
408     CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
409     vector<CTransaction> txVariants;
410     while (!ssData.empty())
411     {
412         try {
413             CTransaction tx;
414             ssData >> tx;
415             txVariants.push_back(tx);
416         }
417         catch (const std::exception&) {
418             throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
419         }
420     }
421
422     if (txVariants.empty())
423         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Missing transaction");
424
425     // mergedTx will end up with all the signatures; it
426     // starts as a clone of the rawtx:
427     CTransaction mergedTx(txVariants[0]);
428     bool fComplete = true;
429
430     // Fetch previous transactions (inputs):
431     map<COutPoint, CScript> mapPrevOut;
432     for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
433     {
434         CTransaction tempTx;
435         MapPrevTx mapPrevTx;
436         CTxDB txdb("r");
437         map<uint256, CTxIndex> unused;
438         bool fInvalid;
439
440         // FetchInputs aborts on failure, so we go one at a time.
441         tempTx.vin.push_back(mergedTx.vin[i]);
442         tempTx.FetchInputs(txdb, unused, false, false, mapPrevTx, fInvalid);
443
444         // Copy results into mapPrevOut:
445         BOOST_FOREACH(const CTxIn& txin, tempTx.vin)
446         {
447             const uint256& prevHash = txin.prevout.hash;
448             if (mapPrevTx.count(prevHash) && mapPrevTx[prevHash].second.vout.size()>txin.prevout.n)
449                 mapPrevOut[txin.prevout] = mapPrevTx[prevHash].second.vout[txin.prevout.n].scriptPubKey;
450         }
451     }
452
453     bool fGivenKeys = false;
454     CBasicKeyStore tempKeystore;
455     if (params.size() > 2 && params[2].type() != null_type)
456     {
457         fGivenKeys = true;
458         Array keys = params[2].get_array();
459         BOOST_FOREACH(Value k, keys)
460         {
461             CBitcoinSecret vchSecret;
462             bool fGood = vchSecret.SetString(k.get_str());
463             if (!fGood)
464                 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
465             CKey key;
466             bool fCompressed;
467             CSecret secret = vchSecret.GetSecret(fCompressed);
468             key.SetSecret(secret, fCompressed);
469             tempKeystore.AddKey(key);
470         }
471     }
472     else
473         EnsureWalletIsUnlocked();
474
475     // Add previous txouts given in the RPC call:
476     if (params.size() > 1 && params[1].type() != null_type)
477     {
478         Array prevTxs = params[1].get_array();
479         BOOST_FOREACH(Value& p, prevTxs)
480         {
481             if (p.type() != obj_type)
482                 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}");
483
484             Object prevOut = p.get_obj();
485
486             RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type));
487
488             string txidHex = find_value(prevOut, "txid").get_str();
489             if (!IsHex(txidHex))
490                 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "txid must be hexadecimal");
491             uint256 txid;
492             txid.SetHex(txidHex);
493
494             int nOut = find_value(prevOut, "vout").get_int();
495             if (nOut < 0)
496                 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive");
497
498             string pkHex = find_value(prevOut, "scriptPubKey").get_str();
499             if (!IsHex(pkHex))
500                 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "scriptPubKey must be hexadecimal");
501             vector<unsigned char> pkData(ParseHex(pkHex));
502             CScript scriptPubKey(pkData.begin(), pkData.end());
503
504             COutPoint outpoint(txid, nOut);
505             if (mapPrevOut.count(outpoint))
506             {
507                 // Complain if scriptPubKey doesn't match
508                 if (mapPrevOut[outpoint] != scriptPubKey)
509                 {
510                     string err("Previous output scriptPubKey mismatch:\n");
511                     err = err + mapPrevOut[outpoint].ToString() + "\nvs:\n"+
512                         scriptPubKey.ToString();
513                     throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
514                 }
515             }
516             else
517                 mapPrevOut[outpoint] = scriptPubKey;
518
519             // if redeemScript given and not using the local wallet (private keys
520             // given), add redeemScript to the tempKeystore so it can be signed:
521             Value v = find_value(prevOut, "redeemScript");
522             if (fGivenKeys && scriptPubKey.IsPayToScriptHash())
523             {
524                 RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type)("redeemScript",str_type));
525                 Value v = find_value(prevOut, "redeemScript");
526                 if (!(v == Value::null))
527                 {
528                     vector<unsigned char> rsData(ParseHexV(v, "redeemScript"));
529                     CScript redeemScript(rsData.begin(), rsData.end());
530                     tempKeystore.AddCScript(redeemScript);
531                 }
532             }
533         }
534     }
535
536     const CKeyStore& keystore = (fGivenKeys ? tempKeystore : *pwalletMain);
537
538     int nHashType = SIGHASH_ALL;
539     if (params.size() > 3 && params[3].type() != null_type)
540     {
541         static map<string, int> mapSigHashValues =
542             boost::assign::map_list_of
543             (string("ALL"), int(SIGHASH_ALL))
544             (string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY))
545             (string("NONE"), int(SIGHASH_NONE))
546             (string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY))
547             (string("SINGLE"), int(SIGHASH_SINGLE))
548             (string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY))
549             ;
550         string strHashType = params[3].get_str();
551         if (mapSigHashValues.count(strHashType))
552             nHashType = mapSigHashValues[strHashType];
553         else
554             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid sighash param");
555     }
556
557     bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
558
559     // Sign what we can:
560     for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
561     {
562         CTxIn& txin = mergedTx.vin[i];
563         if (mapPrevOut.count(txin.prevout) == 0)
564         {
565             fComplete = false;
566             continue;
567         }
568         const CScript& prevPubKey = mapPrevOut[txin.prevout];
569
570         txin.scriptSig.clear();
571         // Only sign SIGHASH_SINGLE if there's a corresponding output:
572         if (!fHashSingle || (i < mergedTx.vout.size()))
573             SignSignature(keystore, prevPubKey, mergedTx, i, nHashType);
574
575         // ... and merge in other signatures:
576         BOOST_FOREACH(const CTransaction& txv, txVariants)
577         {
578             txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
579         }
580         if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, STRICT_FLAGS, 0))
581             fComplete = false;
582     }
583
584     Object result;
585     CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
586     ssTx << mergedTx;
587     result.push_back(Pair("hex", HexStr(ssTx.begin(), ssTx.end())));
588     result.push_back(Pair("complete", fComplete));
589
590     return result;
591 }
592
593 Value sendrawtransaction(const Array& params, bool fHelp)
594 {
595     if (fHelp || params.size() < 1 || params.size() > 1)
596         throw runtime_error(
597             "sendrawtransaction <hex string>\n"
598             "Submits raw transaction (serialized, hex-encoded) to local node and network.");
599
600     RPCTypeCheck(params, list_of(str_type));
601
602     // parse hex string from parameter
603     vector<unsigned char> txData(ParseHex(params[0].get_str()));
604     CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
605     CTransaction tx;
606
607     // deserialize binary data stream
608     try {
609         ssData >> tx;
610     }
611     catch (const std::exception&) {
612         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
613     }
614     uint256 hashTx = tx.GetHash();
615
616     // See if the transaction is already in a block
617     // or in the memory pool:
618     CTransaction existingTx;
619     uint256 hashBlock = 0;
620     if (GetTransaction(hashTx, existingTx, hashBlock))
621     {
622         if (hashBlock != 0)
623             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("transaction already in block ")+hashBlock.GetHex());
624         // Not in block, but already in the memory pool; will drop
625         // through to re-relay it.
626     }
627     else
628     {
629         // push to local node
630         CTxDB txdb("r");
631         if (!tx.AcceptToMemoryPool(txdb))
632             throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX rejected");
633
634         SyncWithWallets(tx, NULL, true);
635     }
636     RelayTransaction(tx, hashTx);
637
638     return hashTx.GetHex();
639 }
640
641 Value createmultisig(const Array& params, bool fHelp)
642 {
643     if (fHelp || params.size() < 2 || params.size() > 3)
644     {
645         string msg = "createmultisig <nrequired> <'[\"key\",\"key\"]'>\n"
646             "\nCreates a multi-signature address with n signature of m keys required.\n"
647             "It returns a json object with the address and redeemScript.";
648         throw runtime_error(msg);
649     }
650
651     int nRequired = params[0].get_int();
652     const Array& keys = params[1].get_array();
653
654     // Gather public keys
655     if (nRequired < 1)
656         throw runtime_error("a multisignature address must require at least one key to redeem");
657     if ((int)keys.size() < nRequired)
658         throw runtime_error(
659             strprintf("not enough keys supplied "
660                       "(got %" PRIszu " keys, but need at least %d to redeem)", keys.size(), nRequired));
661     if (keys.size() > 16)
662         throw runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number");
663     std::vector<CKey> pubkeys;
664     pubkeys.resize(keys.size());
665     for (unsigned int i = 0; i < keys.size(); i++)
666     {
667         const std::string& ks = keys[i].get_str();
668
669         // Case 1: Bitcoin address and we have full public key:
670         CBitcoinAddress address(ks);
671         if (address.IsValid())
672         {
673             CKeyID keyID;
674             if (!address.GetKeyID(keyID))
675                 throw runtime_error(
676                     strprintf("%s does not refer to a key",ks.c_str()));
677             CPubKey vchPubKey;
678             if (!pwalletMain->GetPubKey(keyID, vchPubKey))
679                 throw runtime_error(
680                     strprintf("no full public key for address %s",ks.c_str()));
681             if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
682                 throw runtime_error(" Invalid public key: "+ks);
683         }
684
685         // Case 2: hex public key
686         else if (IsHex(ks))
687         {
688             CPubKey vchPubKey(ParseHex(ks));
689             if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
690                 throw runtime_error(" Invalid public key: "+ks);
691         }
692         else
693         {
694             throw runtime_error(" Invalid public key: "+ks);
695         }
696     }
697
698     // Construct using pay-to-script-hash:
699     CScript inner;
700     inner.SetMultisig(nRequired, pubkeys);
701
702     if (inner.size() > MAX_SCRIPT_ELEMENT_SIZE)
703         throw runtime_error(
704             strprintf("redeemScript exceeds size limit: %" PRIszu " > %d", inner.size(), MAX_SCRIPT_ELEMENT_SIZE));
705
706     CScriptID innerID = inner.GetID();
707     CBitcoinAddress address(innerID);
708
709     Object result;
710     result.push_back(Pair("address", address.ToString()));
711     result.push_back(Pair("redeemScript", HexStr(inner.begin(), inner.end())));
712
713     return result;
714 }