gettransaction: use pubkey pair instead of key view.
[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     string strAccount;
648
649     // Gather public keys
650     if (nRequired < 1)
651         throw runtime_error("a multisignature address must require at least one key to redeem");
652     if ((int)keys.size() < nRequired)
653         throw runtime_error(
654             strprintf("not enough keys supplied "
655                       "(got %" PRIszu " keys, but need at least %d to redeem)", keys.size(), nRequired));
656     if (keys.size() > 16)
657         throw runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number");
658     std::vector<CKey> pubkeys;
659     pubkeys.resize(keys.size());
660     for (unsigned int i = 0; i < keys.size(); i++)
661     {
662         const std::string& ks = keys[i].get_str();
663
664         // Case 1: Bitcoin address and we have full public key:
665         CBitcoinAddress address(ks);
666         if (address.IsValid())
667         {
668             CKeyID keyID;
669             if (!address.GetKeyID(keyID))
670                 throw runtime_error(
671                     strprintf("%s does not refer to a key",ks.c_str()));
672             CPubKey vchPubKey;
673             if (!pwalletMain->GetPubKey(keyID, vchPubKey))
674                 throw runtime_error(
675                     strprintf("no full public key for address %s",ks.c_str()));
676             if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
677                 throw runtime_error(" Invalid public key: "+ks);
678         }
679
680         // Case 2: hex public key
681         else if (IsHex(ks))
682         {
683             CPubKey vchPubKey(ParseHex(ks));
684             if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
685                 throw runtime_error(" Invalid public key: "+ks);
686         }
687         else
688         {
689             throw runtime_error(" Invalid public key: "+ks);
690         }
691     }
692
693     // Construct using pay-to-script-hash:
694     CScript inner;
695     inner.SetMultisig(nRequired, pubkeys);
696
697     if (inner.size() > MAX_SCRIPT_ELEMENT_SIZE)
698         throw runtime_error(
699             strprintf("redeemScript exceeds size limit: %" PRIszu " > %d", inner.size(), MAX_SCRIPT_ELEMENT_SIZE));
700
701     CScriptID innerID = inner.GetID();
702     CBitcoinAddress address(innerID);
703
704     Object result;
705     result.push_back(Pair("address", address.ToString()));
706     result.push_back(Pair("redeemScript", HexStr(inner.begin(), inner.end())));
707
708     return result;
709 }