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