Raw transactions: TX_PUBKEY_DROP parsing
[novacoin.git] / src / rpcrawtransaction.cpp
1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6 #include <boost/assign/list_of.hpp>
7
8 #include "base58.h"
9 #include "bitcoinrpc.h"
10 #include "txdb.h"
11 #include "init.h"
12 #include "main.h"
13 #include "net.h"
14 #include "wallet.h"
15
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             if (!Solver(scriptPubKey, type, vSolutions))
47             {
48                 out.push_back(Pair("keyVariant", HexStr(vSolutions[0])));
49                 out.push_back(Pair("R", HexStr(vSolutions[1])));
50             }
51         }
52
53         Array a;
54         BOOST_FOREACH(const CTxDestination& addr, addresses)
55             a.push_back(CBitcoinAddress(addr).ToString());
56         out.push_back(Pair("addresses", a));
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     BOOST_FOREACH(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         map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
107         if (mi != mapBlockIndex.end() && (*mi).second)
108         {
109             CBlockIndex* 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, list_of(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         BOOST_FOREACH(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     BOOST_FOREACH(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, list_of(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     BOOST_FOREACH(Value& input, inputs)
265     {
266         const Object& o = input.get_obj();
267
268         const Value& txid_v = find_value(o, "txid");
269         if (txid_v.type() != str_type)
270             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing txid key");
271         string txid = txid_v.get_str();
272         if (!IsHex(txid))
273             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
274
275         const Value& vout_v = find_value(o, "vout");
276         if (vout_v.type() != int_type)
277             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key");
278         int nOutput = vout_v.get_int();
279         if (nOutput < 0)
280             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
281
282         CTxIn in(COutPoint(uint256(txid), nOutput));
283         rawTx.vin.push_back(in);
284     }
285
286     set<CBitcoinAddress> setAddress;
287     BOOST_FOREACH(const Pair& s, sendTo)
288     {
289         CBitcoinAddress address(s.name_);
290         if (!address.IsValid())
291             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid NovaCoin address: ")+s.name_);
292
293         if (setAddress.count(address))
294             throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
295         setAddress.insert(address);
296
297         CScript scriptPubKey;
298         scriptPubKey.SetDestination(address.Get());
299         int64_t nAmount = AmountFromValue(s.value_);
300
301         CTxOut out(nAmount, scriptPubKey);
302         rawTx.vout.push_back(out);
303     }
304
305     if (params.size() == 3)
306     {
307         // Data carrying output
308         CScript scriptPubKey;
309         scriptPubKey << OP_RETURN << ParseHex(params[2].get_str());
310         CTxOut out(0, scriptPubKey);
311         rawTx.vout.push_back(out);
312     }
313
314     CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
315     ss << rawTx;
316     return HexStr(ss.begin(), ss.end());
317 }
318
319 Value decoderawtransaction(const Array& params, bool fHelp)
320 {
321     if (fHelp || params.size() != 1)
322         throw runtime_error(
323             "decoderawtransaction <hex string>\n"
324             "Return a JSON object representing the serialized, hex-encoded transaction.");
325
326     RPCTypeCheck(params, list_of(str_type));
327
328     vector<unsigned char> txData(ParseHex(params[0].get_str()));
329     CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
330     CTransaction tx;
331     try {
332         ssData >> tx;
333     }
334     catch (const std::exception&) {
335         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
336     }
337
338     Object result;
339     TxToJSON(tx, 0, result);
340
341     return result;
342 }
343
344 Value decodescript(const Array& params, bool fHelp)
345 {
346     if (fHelp || params.size() != 1)
347         throw runtime_error(
348             "decodescript <hex string>\n"
349             "Decode a hex-encoded script.");
350
351     RPCTypeCheck(params, list_of(str_type));
352
353     Object r;
354     CScript script;
355     if (params[0].get_str().size() > 0){
356         vector<unsigned char> scriptData(ParseHexV(params[0], "argument"));
357         script = CScript(scriptData.begin(), scriptData.end());
358     } else {
359         // Empty scripts are valid
360     }
361     ScriptPubKeyToJSON(script, r, false);
362
363     r.push_back(Pair("p2sh", CBitcoinAddress(script.GetID()).ToString()));
364     return r;
365 }
366
367 Value signrawtransaction(const Array& params, bool fHelp)
368 {
369     if (fHelp || params.size() < 1 || params.size() > 4)
370         throw runtime_error(
371             "signrawtransaction <hex string> '[{\"txid\":txid,\"vout\":n,\"scriptPubKey\":hex,\"redeemScript\":hex},...]' '[<privatekey1>,...]' [sighashtype=\"ALL\"]\n"
372             "Sign inputs for raw transaction (serialized, hex-encoded).\n"
373             "Second optional argument (may be null) is an array of previous transaction outputs that\n"
374             "this transaction depends on but may not yet be in the blockchain.\n"
375             "Third optional argument (may be null) is an array of base58-encoded private\n"
376             "keys that, if given, will be the only keys used to sign the transaction.\n"
377             "Fourth optional argument is a string that is one of six values; ALL, NONE, SINGLE or\n"
378             "ALL|ANYONECANPAY, NONE|ANYONECANPAY, SINGLE|ANYONECANPAY.\n"
379             "Returns json object with keys:\n"
380             "  hex : raw transaction with signature(s) (hex-encoded string)\n"
381             "  complete : 1 if transaction has a complete set of signature (0 if not)"
382             + HelpRequiringPassphrase());
383
384     RPCTypeCheck(params, list_of(str_type)(array_type)(array_type)(str_type), true);
385
386     vector<unsigned char> txData(ParseHex(params[0].get_str()));
387     CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
388     vector<CTransaction> txVariants;
389     while (!ssData.empty())
390     {
391         try {
392             CTransaction tx;
393             ssData >> tx;
394             txVariants.push_back(tx);
395         }
396         catch (const std::exception&) {
397             throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
398         }
399     }
400
401     if (txVariants.empty())
402         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Missing transaction");
403
404     // mergedTx will end up with all the signatures; it
405     // starts as a clone of the rawtx:
406     CTransaction mergedTx(txVariants[0]);
407     bool fComplete = true;
408
409     // Fetch previous transactions (inputs):
410     map<COutPoint, CScript> mapPrevOut;
411     for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
412     {
413         CTransaction tempTx;
414         MapPrevTx mapPrevTx;
415         CTxDB txdb("r");
416         map<uint256, CTxIndex> unused;
417         bool fInvalid;
418
419         // FetchInputs aborts on failure, so we go one at a time.
420         tempTx.vin.push_back(mergedTx.vin[i]);
421         tempTx.FetchInputs(txdb, unused, false, false, mapPrevTx, fInvalid);
422
423         // Copy results into mapPrevOut:
424         BOOST_FOREACH(const CTxIn& txin, tempTx.vin)
425         {
426             const uint256& prevHash = txin.prevout.hash;
427             if (mapPrevTx.count(prevHash) && mapPrevTx[prevHash].second.vout.size()>txin.prevout.n)
428                 mapPrevOut[txin.prevout] = mapPrevTx[prevHash].second.vout[txin.prevout.n].scriptPubKey;
429         }
430     }
431
432     bool fGivenKeys = false;
433     CBasicKeyStore tempKeystore;
434     if (params.size() > 2 && params[2].type() != null_type)
435     {
436         fGivenKeys = true;
437         Array keys = params[2].get_array();
438         BOOST_FOREACH(Value k, keys)
439         {
440             CBitcoinSecret vchSecret;
441             bool fGood = vchSecret.SetString(k.get_str());
442             if (!fGood)
443                 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
444             CKey key;
445             bool fCompressed;
446             CSecret secret = vchSecret.GetSecret(fCompressed);
447             key.SetSecret(secret, fCompressed);
448             tempKeystore.AddKey(key);
449         }
450     }
451     else
452         EnsureWalletIsUnlocked();
453
454     // Add previous txouts given in the RPC call:
455     if (params.size() > 1 && params[1].type() != null_type)
456     {
457         Array prevTxs = params[1].get_array();
458         BOOST_FOREACH(Value& p, prevTxs)
459         {
460             if (p.type() != obj_type)
461                 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}");
462
463             Object prevOut = p.get_obj();
464
465             RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type));
466
467             string txidHex = find_value(prevOut, "txid").get_str();
468             if (!IsHex(txidHex))
469                 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "txid must be hexadecimal");
470             uint256 txid;
471             txid.SetHex(txidHex);
472
473             int nOut = find_value(prevOut, "vout").get_int();
474             if (nOut < 0)
475                 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive");
476
477             string pkHex = find_value(prevOut, "scriptPubKey").get_str();
478             if (!IsHex(pkHex))
479                 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "scriptPubKey must be hexadecimal");
480             vector<unsigned char> pkData(ParseHex(pkHex));
481             CScript scriptPubKey(pkData.begin(), pkData.end());
482
483             COutPoint outpoint(txid, nOut);
484             if (mapPrevOut.count(outpoint))
485             {
486                 // Complain if scriptPubKey doesn't match
487                 if (mapPrevOut[outpoint] != scriptPubKey)
488                 {
489                     string err("Previous output scriptPubKey mismatch:\n");
490                     err = err + mapPrevOut[outpoint].ToString() + "\nvs:\n"+
491                         scriptPubKey.ToString();
492                     throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
493                 }
494             }
495             else
496                 mapPrevOut[outpoint] = scriptPubKey;
497
498             // if redeemScript given and not using the local wallet (private keys
499             // given), add redeemScript to the tempKeystore so it can be signed:
500             Value v = find_value(prevOut, "redeemScript");
501             if (fGivenKeys && scriptPubKey.IsPayToScriptHash())
502             {
503                 RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type)("redeemScript",str_type));
504                 Value v = find_value(prevOut, "redeemScript");
505                 if (!(v == Value::null))
506                 {
507                     vector<unsigned char> rsData(ParseHexV(v, "redeemScript"));
508                     CScript redeemScript(rsData.begin(), rsData.end());
509                     tempKeystore.AddCScript(redeemScript);
510                 }
511             }
512         }
513     }
514
515     const CKeyStore& keystore = (fGivenKeys ? tempKeystore : *pwalletMain);
516
517     int nHashType = SIGHASH_ALL;
518     if (params.size() > 3 && params[3].type() != null_type)
519     {
520         static map<string, int> mapSigHashValues =
521             boost::assign::map_list_of
522             (string("ALL"), int(SIGHASH_ALL))
523             (string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY))
524             (string("NONE"), int(SIGHASH_NONE))
525             (string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY))
526             (string("SINGLE"), int(SIGHASH_SINGLE))
527             (string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY))
528             ;
529         string strHashType = params[3].get_str();
530         if (mapSigHashValues.count(strHashType))
531             nHashType = mapSigHashValues[strHashType];
532         else
533             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid sighash param");
534     }
535
536     bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
537
538     // Sign what we can:
539     for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
540     {
541         CTxIn& txin = mergedTx.vin[i];
542         if (mapPrevOut.count(txin.prevout) == 0)
543         {
544             fComplete = false;
545             continue;
546         }
547         const CScript& prevPubKey = mapPrevOut[txin.prevout];
548
549         txin.scriptSig.clear();
550         // Only sign SIGHASH_SINGLE if there's a corresponding output:
551         if (!fHashSingle || (i < mergedTx.vout.size()))
552             SignSignature(keystore, prevPubKey, mergedTx, i, nHashType);
553
554         // ... and merge in other signatures:
555         BOOST_FOREACH(const CTransaction& txv, txVariants)
556         {
557             txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
558         }
559         if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, STRICT_FLAGS, 0))
560             fComplete = false;
561     }
562
563     Object result;
564     CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
565     ssTx << mergedTx;
566     result.push_back(Pair("hex", HexStr(ssTx.begin(), ssTx.end())));
567     result.push_back(Pair("complete", fComplete));
568
569     return result;
570 }
571
572 Value sendrawtransaction(const Array& params, bool fHelp)
573 {
574     if (fHelp || params.size() < 1 || params.size() > 1)
575         throw runtime_error(
576             "sendrawtransaction <hex string>\n"
577             "Submits raw transaction (serialized, hex-encoded) to local node and network.");
578
579     RPCTypeCheck(params, list_of(str_type));
580
581     // parse hex string from parameter
582     vector<unsigned char> txData(ParseHex(params[0].get_str()));
583     CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
584     CTransaction tx;
585
586     // deserialize binary data stream
587     try {
588         ssData >> tx;
589     }
590     catch (const std::exception&) {
591         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
592     }
593     uint256 hashTx = tx.GetHash();
594
595     // See if the transaction is already in a block
596     // or in the memory pool:
597     CTransaction existingTx;
598     uint256 hashBlock = 0;
599     if (GetTransaction(hashTx, existingTx, hashBlock))
600     {
601         if (hashBlock != 0)
602             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("transaction already in block ")+hashBlock.GetHex());
603         // Not in block, but already in the memory pool; will drop
604         // through to re-relay it.
605     }
606     else
607     {
608         // push to local node
609         CTxDB txdb("r");
610         if (!tx.AcceptToMemoryPool(txdb))
611             throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX rejected");
612
613         SyncWithWallets(tx, NULL, true);
614     }
615     RelayTransaction(tx, hashTx);
616
617     return hashTx.GetHex();
618 }
619
620 Value createmultisig(const Array& params, bool fHelp)
621 {
622     if (fHelp || params.size() < 2 || params.size() > 3)
623     {
624         string msg = "createmultisig <nrequired> <'[\"key\",\"key\"]'>\n"
625             "\nCreates a multi-signature address with n signature of m keys required.\n"
626             "It returns a json object with the address and redeemScript.";
627         throw runtime_error(msg);
628     }
629
630     int nRequired = params[0].get_int();
631     const Array& keys = params[1].get_array();
632     string strAccount;
633
634     // Gather public keys
635     if (nRequired < 1)
636         throw runtime_error("a multisignature address must require at least one key to redeem");
637     if ((int)keys.size() < nRequired)
638         throw runtime_error(
639             strprintf("not enough keys supplied "
640                       "(got %" PRIszu " keys, but need at least %d to redeem)", keys.size(), nRequired));
641     if (keys.size() > 16)
642         throw runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number");
643     std::vector<CKey> pubkeys;
644     pubkeys.resize(keys.size());
645     for (unsigned int i = 0; i < keys.size(); i++)
646     {
647         const std::string& ks = keys[i].get_str();
648
649         // Case 1: Bitcoin address and we have full public key:
650         CBitcoinAddress address(ks);
651         if (address.IsValid())
652         {
653             CKeyID keyID;
654             if (!address.GetKeyID(keyID))
655                 throw runtime_error(
656                     strprintf("%s does not refer to a key",ks.c_str()));
657             CPubKey vchPubKey;
658             if (!pwalletMain->GetPubKey(keyID, vchPubKey))
659                 throw runtime_error(
660                     strprintf("no full public key for address %s",ks.c_str()));
661             if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
662                 throw runtime_error(" Invalid public key: "+ks);
663         }
664
665         // Case 2: hex public key
666         else if (IsHex(ks))
667         {
668             CPubKey vchPubKey(ParseHex(ks));
669             if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey))
670                 throw runtime_error(" Invalid public key: "+ks);
671         }
672         else
673         {
674             throw runtime_error(" Invalid public key: "+ks);
675         }
676     }
677
678     // Construct using pay-to-script-hash:
679     CScript inner;
680     inner.SetMultisig(nRequired, pubkeys);
681
682     if (inner.size() > MAX_SCRIPT_ELEMENT_SIZE)
683         throw runtime_error(
684             strprintf("redeemScript exceeds size limit: %" PRIszu " > %d", inner.size(), MAX_SCRIPT_ELEMENT_SIZE));
685
686     CScriptID innerID = inner.GetID();
687     CBitcoinAddress address(innerID);
688
689     Object result;
690     result.push_back(Pair("address", address.ToString()));
691     result.push_back(Pair("redeemScript", HexStr(inner.begin(), inner.end())));
692
693     return result;
694 }