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