Merge branch 'patch' of ssh://github.com/svost/novacoin into svost-patch
[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", 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         if (!address.IsValid())
297         {
298             CMalleablePubKey mpk(s.name_);
299             if (!mpk.IsValid())
300                 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid output destination: ")+s.name_);
301
302             CPubKey keyVariant, R;
303             mpk.GetVariant(R, keyVariant);
304             scriptPubKey.SetDestination(R, keyVariant);
305         }
306         else
307         {
308             scriptPubKey.SetDestination(address.Get());
309             if (setAddress.count(address))
310                 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
311             setAddress.insert(address);
312         }
313
314         int64_t nAmount = AmountFromValue(s.value_);
315
316         CTxOut out(nAmount, scriptPubKey);
317         rawTx.vout.push_back(out);
318     }
319
320     if (params.size() == 3)
321     {
322         // Data carrying output
323         CScript scriptPubKey;
324         scriptPubKey << OP_RETURN << ParseHex(params[2].get_str());
325         CTxOut out(0, scriptPubKey);
326         rawTx.vout.push_back(out);
327     }
328
329     CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
330     ss << rawTx;
331     return HexStr(ss.begin(), ss.end());
332 }
333
334 Value decoderawtransaction(const Array& params, bool fHelp)
335 {
336     if (fHelp || params.size() != 1)
337         throw runtime_error(
338             "decoderawtransaction <hex string>\n"
339             "Return a JSON object representing the serialized, hex-encoded transaction.");
340
341     RPCTypeCheck(params, list_of(str_type));
342
343     vector<unsigned char> txData(ParseHex(params[0].get_str()));
344     CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
345     CTransaction tx;
346     try {
347         ssData >> tx;
348     }
349     catch (const std::exception&) {
350         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
351     }
352
353     Object result;
354     TxToJSON(tx, 0, result);
355
356     return result;
357 }
358
359 Value decodescript(const Array& params, bool fHelp)
360 {
361     if (fHelp || params.size() != 1)
362         throw runtime_error(
363             "decodescript <hex string>\n"
364             "Decode a hex-encoded script.");
365
366     RPCTypeCheck(params, list_of(str_type));
367
368     Object r;
369     CScript script;
370     if (params[0].get_str().size() > 0){
371         vector<unsigned char> scriptData(ParseHexV(params[0], "argument"));
372         script = CScript(scriptData.begin(), scriptData.end());
373     } else {
374         // Empty scripts are valid
375     }
376     ScriptPubKeyToJSON(script, r, false);
377
378     r.push_back(Pair("p2sh", CBitcoinAddress(script.GetID()).ToString()));
379     return r;
380 }
381
382 Value signrawtransaction(const Array& params, bool fHelp)
383 {
384     if (fHelp || params.size() < 1 || params.size() > 4)
385         throw runtime_error(
386             "signrawtransaction <hex string> '[{\"txid\":txid,\"vout\":n,\"scriptPubKey\":hex,\"redeemScript\":hex},...]' '[<privatekey1>,...]' [sighashtype=\"ALL\"]\n"
387             "Sign inputs for raw transaction (serialized, hex-encoded).\n"
388             "Second optional argument (may be null) is an array of previous transaction outputs that\n"
389             "this transaction depends on but may not yet be in the blockchain.\n"
390             "Third optional argument (may be null) is an array of base58-encoded private\n"
391             "keys that, if given, will be the only keys used to sign the transaction.\n"
392             "Fourth optional argument is a string that is one of six values; ALL, NONE, SINGLE or\n"
393             "ALL|ANYONECANPAY, NONE|ANYONECANPAY, SINGLE|ANYONECANPAY.\n"
394             "Returns json object with keys:\n"
395             "  hex : raw transaction with signature(s) (hex-encoded string)\n"
396             "  complete : 1 if transaction has a complete set of signature (0 if not)"
397             + HelpRequiringPassphrase());
398
399     RPCTypeCheck(params, list_of(str_type)(array_type)(array_type)(str_type), true);
400
401     vector<unsigned char> txData(ParseHex(params[0].get_str()));
402     CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
403     vector<CTransaction> txVariants;
404     while (!ssData.empty())
405     {
406         try {
407             CTransaction tx;
408             ssData >> tx;
409             txVariants.push_back(tx);
410         }
411         catch (const std::exception&) {
412             throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
413         }
414     }
415
416     if (txVariants.empty())
417         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Missing transaction");
418
419     // mergedTx will end up with all the signatures; it
420     // starts as a clone of the rawtx:
421     CTransaction mergedTx(txVariants[0]);
422     bool fComplete = true;
423
424     // Fetch previous transactions (inputs):
425     map<COutPoint, CScript> mapPrevOut;
426     for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
427     {
428         CTransaction tempTx;
429         MapPrevTx mapPrevTx;
430         CTxDB txdb("r");
431         map<uint256, CTxIndex> unused;
432         bool fInvalid;
433
434         // FetchInputs aborts on failure, so we go one at a time.
435         tempTx.vin.push_back(mergedTx.vin[i]);
436         tempTx.FetchInputs(txdb, unused, false, false, mapPrevTx, fInvalid);
437
438         // Copy results into mapPrevOut:
439         BOOST_FOREACH(const CTxIn& txin, tempTx.vin)
440         {
441             const uint256& prevHash = txin.prevout.hash;
442             if (mapPrevTx.count(prevHash) && mapPrevTx[prevHash].second.vout.size()>txin.prevout.n)
443                 mapPrevOut[txin.prevout] = mapPrevTx[prevHash].second.vout[txin.prevout.n].scriptPubKey;
444         }
445     }
446
447     bool fGivenKeys = false;
448     CBasicKeyStore tempKeystore;
449     if (params.size() > 2 && params[2].type() != null_type)
450     {
451         fGivenKeys = true;
452         Array keys = params[2].get_array();
453         BOOST_FOREACH(Value k, keys)
454         {
455             CBitcoinSecret vchSecret;
456             bool fGood = vchSecret.SetString(k.get_str());
457             if (!fGood)
458                 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
459             CKey key;
460             bool fCompressed;
461             CSecret secret = vchSecret.GetSecret(fCompressed);
462             key.SetSecret(secret, fCompressed);
463             tempKeystore.AddKey(key);
464         }
465     }
466     else
467         EnsureWalletIsUnlocked();
468
469     // Add previous txouts given in the RPC call:
470     if (params.size() > 1 && params[1].type() != null_type)
471     {
472         Array prevTxs = params[1].get_array();
473         BOOST_FOREACH(Value& p, prevTxs)
474         {
475             if (p.type() != obj_type)
476                 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}");
477
478             Object prevOut = p.get_obj();
479
480             RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type));
481
482             string txidHex = find_value(prevOut, "txid").get_str();
483             if (!IsHex(txidHex))
484                 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "txid must be hexadecimal");
485             uint256 txid;
486             txid.SetHex(txidHex);
487
488             int nOut = find_value(prevOut, "vout").get_int();
489             if (nOut < 0)
490                 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive");
491
492             string pkHex = find_value(prevOut, "scriptPubKey").get_str();
493             if (!IsHex(pkHex))
494                 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "scriptPubKey must be hexadecimal");
495             vector<unsigned char> pkData(ParseHex(pkHex));
496             CScript scriptPubKey(pkData.begin(), pkData.end());
497
498             COutPoint outpoint(txid, nOut);
499             if (mapPrevOut.count(outpoint))
500             {
501                 // Complain if scriptPubKey doesn't match
502                 if (mapPrevOut[outpoint] != scriptPubKey)
503                 {
504                     string err("Previous output scriptPubKey mismatch:\n");
505                     err = err + mapPrevOut[outpoint].ToString() + "\nvs:\n"+
506                         scriptPubKey.ToString();
507                     throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
508                 }
509             }
510             else
511                 mapPrevOut[outpoint] = scriptPubKey;
512
513             // if redeemScript given and not using the local wallet (private keys
514             // given), add redeemScript to the tempKeystore so it can be signed:
515             Value v = find_value(prevOut, "redeemScript");
516             if (fGivenKeys && scriptPubKey.IsPayToScriptHash())
517             {
518                 RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type)("redeemScript",str_type));
519                 Value v = find_value(prevOut, "redeemScript");
520                 if (!(v == Value::null))
521                 {
522                     vector<unsigned char> rsData(ParseHexV(v, "redeemScript"));
523                     CScript redeemScript(rsData.begin(), rsData.end());
524                     tempKeystore.AddCScript(redeemScript);
525                 }
526             }
527         }
528     }
529
530     const CKeyStore& keystore = (fGivenKeys ? tempKeystore : *pwalletMain);
531
532     int nHashType = SIGHASH_ALL;
533     if (params.size() > 3 && params[3].type() != null_type)
534     {
535         static map<string, int> mapSigHashValues =
536             boost::assign::map_list_of
537             (string("ALL"), int(SIGHASH_ALL))
538             (string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY))
539             (string("NONE"), int(SIGHASH_NONE))
540             (string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY))
541             (string("SINGLE"), int(SIGHASH_SINGLE))
542             (string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY))
543             ;
544         string strHashType = params[3].get_str();
545         if (mapSigHashValues.count(strHashType))
546             nHashType = mapSigHashValues[strHashType];
547         else
548             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid sighash param");
549     }
550
551     bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
552
553     // Sign what we can:
554     for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
555     {
556         CTxIn& txin = mergedTx.vin[i];
557         if (mapPrevOut.count(txin.prevout) == 0)
558         {
559             fComplete = false;
560             continue;
561         }
562         const CScript& prevPubKey = mapPrevOut[txin.prevout];
563
564         txin.scriptSig.clear();
565         // Only sign SIGHASH_SINGLE if there's a corresponding output:
566         if (!fHashSingle || (i < mergedTx.vout.size()))
567             SignSignature(keystore, prevPubKey, mergedTx, i, nHashType);
568
569         // ... and merge in other signatures:
570         BOOST_FOREACH(const CTransaction& txv, txVariants)
571         {
572             txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
573         }
574         if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, STRICT_FLAGS, 0))
575             fComplete = false;
576     }
577
578     Object result;
579     CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
580     ssTx << mergedTx;
581     result.push_back(Pair("hex", HexStr(ssTx.begin(), ssTx.end())));
582     result.push_back(Pair("complete", fComplete));
583
584     return result;
585 }
586
587 Value sendrawtransaction(const Array& params, bool fHelp)
588 {
589     if (fHelp || params.size() < 1 || params.size() > 1)
590         throw runtime_error(
591             "sendrawtransaction <hex string>\n"
592             "Submits raw transaction (serialized, hex-encoded) to local node and network.");
593
594     RPCTypeCheck(params, list_of(str_type));
595
596     // parse hex string from parameter
597     vector<unsigned char> txData(ParseHex(params[0].get_str()));
598     CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
599     CTransaction tx;
600
601     // deserialize binary data stream
602     try {
603         ssData >> tx;
604     }
605     catch (const std::exception&) {
606         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
607     }
608     uint256 hashTx = tx.GetHash();
609
610     // See if the transaction is already in a block
611     // or in the memory pool:
612     CTransaction existingTx;
613     uint256 hashBlock = 0;
614     if (GetTransaction(hashTx, existingTx, hashBlock))
615     {
616         if (hashBlock != 0)
617             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("transaction already in block ")+hashBlock.GetHex());
618         // Not in block, but already in the memory pool; will drop
619         // through to re-relay it.
620     }
621     else
622     {
623         // push to local node
624         CTxDB txdb("r");
625         if (!tx.AcceptToMemoryPool(txdb))
626             throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX rejected");
627
628         SyncWithWallets(tx, NULL, true);
629     }
630     RelayTransaction(tx, hashTx);
631
632     return hashTx.GetHex();
633 }
634
635 Value createmultisig(const Array& params, bool fHelp)
636 {
637     if (fHelp || params.size() < 2 || params.size() > 3)
638     {
639         string msg = "createmultisig <nrequired> <'[\"key\",\"key\"]'>\n"
640             "\nCreates a multi-signature address with n signature of m keys required.\n"
641             "It returns a json object with the address and redeemScript.";
642         throw runtime_error(msg);
643     }
644
645     int nRequired = params[0].get_int();
646     const Array& keys = params[1].get_array();
647
648     // Gather public keys
649     if (nRequired < 1)
650         throw runtime_error("a multisignature address must require at least one key to redeem");
651     if ((int)keys.size() < nRequired)
652         throw runtime_error(
653             strprintf("not enough keys supplied "
654                       "(got %" PRIszu " keys, but need at least %d to redeem)", keys.size(), nRequired));
655     if (keys.size() > 16)
656         throw runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number");
657     std::vector<CKey> pubkeys;
658     pubkeys.resize(keys.size());
659     for (unsigned int i = 0; i < keys.size(); i++)
660     {
661         const std::string& ks = keys[i].get_str();
662
663         // Case 1: Bitcoin address and we have full public key:
664         CBitcoinAddress address(ks);
665         if (address.IsValid())
666         {
667             CKeyID keyID;
668             if (!address.GetKeyID(keyID))
669                 throw runtime_error(
670                     strprintf("%s does not refer to a key",ks.c_str()));
671             CPubKey vchPubKey;
672             if (!pwalletMain->GetPubKey(keyID, vchPubKey))
673                 throw runtime_error(
674                     strprintf("no full public key for address %s",ks.c_str()));
675             if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
676                 throw runtime_error(" Invalid public key: "+ks);
677         }
678
679         // Case 2: hex public key
680         else if (IsHex(ks))
681         {
682             CPubKey vchPubKey(ParseHex(ks));
683             if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
684                 throw runtime_error(" Invalid public key: "+ks);
685         }
686         else
687         {
688             throw runtime_error(" Invalid public key: "+ks);
689         }
690     }
691
692     // Construct using pay-to-script-hash:
693     CScript inner;
694     inner.SetMultisig(nRequired, pubkeys);
695
696     if (inner.size() > MAX_SCRIPT_ELEMENT_SIZE)
697         throw runtime_error(
698             strprintf("redeemScript exceeds size limit: %" PRIszu " > %d", inner.size(), MAX_SCRIPT_ELEMENT_SIZE));
699
700     CScriptID innerID = inner.GetID();
701     CBitcoinAddress address(innerID);
702
703     Object result;
704     result.push_back(Pair("address", address.ToString()));
705     result.push_back(Pair("redeemScript", HexStr(inner.begin(), inner.end())));
706
707     return result;
708 }