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