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