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