]> Git Repo - VerusCoin.git/blob - src/bitcoin-tx.cpp
[Univalue] add univalue over subtree
[VerusCoin.git] / src / bitcoin-tx.cpp
1 // Copyright (c) 2009-2014 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5 #include "base58.h"
6 #include "clientversion.h"
7 #include "coins.h"
8 #include "consensus/consensus.h"
9 #include "core_io.h"
10 #include "keystore.h"
11 #include "primitives/transaction.h"
12 #include "script/script.h"
13 #include "script/sign.h"
14 #include <univalue.h>
15 #include "util.h"
16 #include "utilmoneystr.h"
17 #include "utilstrencodings.h"
18
19 #include <stdio.h>
20
21 #include <boost/algorithm/string.hpp>
22 #include <boost/assign/list_of.hpp>
23
24 using namespace std;
25
26 static bool fCreateBlank;
27 static map<string,UniValue> registers;
28
29 static bool AppInitRawTx(int argc, char* argv[])
30 {
31     //
32     // Parameters
33     //
34     ParseParameters(argc, argv);
35
36     // Check for -testnet or -regtest parameter (Params() calls are only valid after this clause)
37     if (!SelectParamsFromCommandLine()) {
38         fprintf(stderr, "Error: Invalid combination of -regtest and -testnet.\n");
39         return false;
40     }
41
42     fCreateBlank = GetBoolArg("-create", false);
43
44     if (argc<2 || mapArgs.count("-?") || mapArgs.count("-h") || mapArgs.count("-help"))
45     {
46         // First part of help message is specific to this utility
47         std::string strUsage = _("Zcash zcash-tx utility version") + " " + FormatFullVersion() + "\n\n" +
48             _("Usage:") + "\n" +
49               "  zcash-tx [options] <hex-tx> [commands]  " + _("Update hex-encoded zcash transaction") + "\n" +
50               "  zcash-tx [options] -create [commands]   " + _("Create hex-encoded zcash transaction") + "\n" +
51               "\n";
52
53         fprintf(stdout, "%s", strUsage.c_str());
54
55         strUsage = HelpMessageGroup(_("Options:"));
56         strUsage += HelpMessageOpt("-?", _("This help message"));
57         strUsage += HelpMessageOpt("-create", _("Create new, empty TX."));
58         strUsage += HelpMessageOpt("-json", _("Select JSON output"));
59         strUsage += HelpMessageOpt("-txid", _("Output only the hex-encoded transaction id of the resultant transaction."));
60         strUsage += HelpMessageOpt("-regtest", _("Enter regression test mode, which uses a special chain in which blocks can be solved instantly."));
61         strUsage += HelpMessageOpt("-testnet", _("Use the test network"));
62
63         fprintf(stdout, "%s", strUsage.c_str());
64
65         strUsage = HelpMessageGroup(_("Commands:"));
66         strUsage += HelpMessageOpt("delin=N", _("Delete input N from TX"));
67         strUsage += HelpMessageOpt("delout=N", _("Delete output N from TX"));
68         strUsage += HelpMessageOpt("in=TXID:VOUT", _("Add input to TX"));
69         strUsage += HelpMessageOpt("locktime=N", _("Set TX lock time to N"));
70         strUsage += HelpMessageOpt("nversion=N", _("Set TX version to N"));
71         strUsage += HelpMessageOpt("outaddr=VALUE:ADDRESS", _("Add address-based output to TX"));
72         strUsage += HelpMessageOpt("outscript=VALUE:SCRIPT", _("Add raw script output to TX"));
73         strUsage += HelpMessageOpt("sign=SIGHASH-FLAGS", _("Add zero or more signatures to transaction") + ". " +
74             _("This command requires JSON registers:") +
75             _("prevtxs=JSON object") + ", " +
76             _("privatekeys=JSON object") + ". " +
77             _("See signrawtransaction docs for format of sighash flags, JSON objects."));
78         fprintf(stdout, "%s", strUsage.c_str());
79
80         strUsage = HelpMessageGroup(_("Register Commands:"));
81         strUsage += HelpMessageOpt("load=NAME:FILENAME", _("Load JSON file FILENAME into register NAME"));
82         strUsage += HelpMessageOpt("set=NAME:JSON-STRING", _("Set register NAME to given JSON-STRING"));
83         fprintf(stdout, "%s", strUsage.c_str());
84
85         return false;
86     }
87     return true;
88 }
89
90 static void RegisterSetJson(const string& key, const string& rawJson)
91 {
92     UniValue val;
93     if (!val.read(rawJson)) {
94         string strErr = "Cannot parse JSON for key " + key;
95         throw runtime_error(strErr);
96     }
97
98     registers[key] = val;
99 }
100
101 static void RegisterSet(const string& strInput)
102 {
103     // separate NAME:VALUE in string
104     size_t pos = strInput.find(':');
105     if ((pos == string::npos) ||
106         (pos == 0) ||
107         (pos == (strInput.size() - 1)))
108         throw runtime_error("Register input requires NAME:VALUE");
109
110     string key = strInput.substr(0, pos);
111     string valStr = strInput.substr(pos + 1, string::npos);
112
113     RegisterSetJson(key, valStr);
114 }
115
116 static void RegisterLoad(const string& strInput)
117 {
118     // separate NAME:FILENAME in string
119     size_t pos = strInput.find(':');
120     if ((pos == string::npos) ||
121         (pos == 0) ||
122         (pos == (strInput.size() - 1)))
123         throw runtime_error("Register load requires NAME:FILENAME");
124
125     string key = strInput.substr(0, pos);
126     string filename = strInput.substr(pos + 1, string::npos);
127
128     FILE *f = fopen(filename.c_str(), "r");
129     if (!f) {
130         string strErr = "Cannot open file " + filename;
131         throw runtime_error(strErr);
132     }
133
134     // load file chunks into one big buffer
135     string valStr;
136     while ((!feof(f)) && (!ferror(f))) {
137         char buf[4096];
138         int bread = fread(buf, 1, sizeof(buf), f);
139         if (bread <= 0)
140             break;
141
142         valStr.insert(valStr.size(), buf, bread);
143     }
144
145     int error = ferror(f);
146     fclose(f);
147
148     if (error) {
149         string strErr = "Error reading file " + filename;
150         throw runtime_error(strErr);
151     }
152
153     // evaluate as JSON buffer register
154     RegisterSetJson(key, valStr);
155 }
156
157 static void MutateTxVersion(CMutableTransaction& tx, const string& cmdVal)
158 {
159     int64_t newVersion = atoi64(cmdVal);
160     if (newVersion < CTransaction::MIN_CURRENT_VERSION || newVersion > CTransaction::MAX_CURRENT_VERSION)
161         throw runtime_error("Invalid TX version requested");
162
163     tx.nVersion = (int) newVersion;
164 }
165
166 static void MutateTxLocktime(CMutableTransaction& tx, const string& cmdVal)
167 {
168     int64_t newLocktime = atoi64(cmdVal);
169     if (newLocktime < 0LL || newLocktime > 0xffffffffLL)
170         throw runtime_error("Invalid TX locktime requested");
171
172     tx.nLockTime = (unsigned int) newLocktime;
173 }
174
175 static void MutateTxAddInput(CMutableTransaction& tx, const string& strInput)
176 {
177     // separate TXID:VOUT in string
178     size_t pos = strInput.find(':');
179     if ((pos == string::npos) ||
180         (pos == 0) ||
181         (pos == (strInput.size() - 1)))
182         throw runtime_error("TX input missing separator");
183
184     // extract and validate TXID
185     string strTxid = strInput.substr(0, pos);
186     if ((strTxid.size() != 64) || !IsHex(strTxid))
187         throw runtime_error("invalid TX input txid");
188     uint256 txid(uint256S(strTxid));
189
190     static const unsigned int minTxOutSz = 9;
191     static const unsigned int maxVout = MAX_BLOCK_SIZE / minTxOutSz;
192
193     // extract and validate vout
194     string strVout = strInput.substr(pos + 1, string::npos);
195     int vout = atoi(strVout);
196     if ((vout < 0) || (vout > (int)maxVout))
197         throw runtime_error("invalid TX input vout");
198
199     // append to transaction input list
200     CTxIn txin(txid, vout);
201     tx.vin.push_back(txin);
202 }
203
204 static void MutateTxAddOutAddr(CMutableTransaction& tx, const string& strInput)
205 {
206     // separate VALUE:ADDRESS in string
207     size_t pos = strInput.find(':');
208     if ((pos == string::npos) ||
209         (pos == 0) ||
210         (pos == (strInput.size() - 1)))
211         throw runtime_error("TX output missing separator");
212
213     // extract and validate VALUE
214     string strValue = strInput.substr(0, pos);
215     CAmount value;
216     if (!ParseMoney(strValue, value))
217         throw runtime_error("invalid TX output value");
218
219     // extract and validate ADDRESS
220     string strAddr = strInput.substr(pos + 1, string::npos);
221     CBitcoinAddress addr(strAddr);
222     if (!addr.IsValid())
223         throw runtime_error("invalid TX output address");
224
225     // build standard output script via GetScriptForDestination()
226     CScript scriptPubKey = GetScriptForDestination(addr.Get());
227
228     // construct TxOut, append to transaction output list
229     CTxOut txout(value, scriptPubKey);
230     tx.vout.push_back(txout);
231 }
232
233 static void MutateTxAddOutScript(CMutableTransaction& tx, const string& strInput)
234 {
235     // separate VALUE:SCRIPT in string
236     size_t pos = strInput.find(':');
237     if ((pos == string::npos) ||
238         (pos == 0))
239         throw runtime_error("TX output missing separator");
240
241     // extract and validate VALUE
242     string strValue = strInput.substr(0, pos);
243     CAmount value;
244     if (!ParseMoney(strValue, value))
245         throw runtime_error("invalid TX output value");
246
247     // extract and validate script
248     string strScript = strInput.substr(pos + 1, string::npos);
249     CScript scriptPubKey = ParseScript(strScript); // throws on err
250
251     // construct TxOut, append to transaction output list
252     CTxOut txout(value, scriptPubKey);
253     tx.vout.push_back(txout);
254 }
255
256 static void MutateTxDelInput(CMutableTransaction& tx, const string& strInIdx)
257 {
258     // parse requested deletion index
259     int inIdx = atoi(strInIdx);
260     if (inIdx < 0 || inIdx >= (int)tx.vin.size()) {
261         string strErr = "Invalid TX input index '" + strInIdx + "'";
262         throw runtime_error(strErr.c_str());
263     }
264
265     // delete input from transaction
266     tx.vin.erase(tx.vin.begin() + inIdx);
267 }
268
269 static void MutateTxDelOutput(CMutableTransaction& tx, const string& strOutIdx)
270 {
271     // parse requested deletion index
272     int outIdx = atoi(strOutIdx);
273     if (outIdx < 0 || outIdx >= (int)tx.vout.size()) {
274         string strErr = "Invalid TX output index '" + strOutIdx + "'";
275         throw runtime_error(strErr.c_str());
276     }
277
278     // delete output from transaction
279     tx.vout.erase(tx.vout.begin() + outIdx);
280 }
281
282 static const unsigned int N_SIGHASH_OPTS = 6;
283 static const struct {
284     const char *flagStr;
285     int flags;
286 } sighashOptions[N_SIGHASH_OPTS] = {
287     {"ALL", SIGHASH_ALL},
288     {"NONE", SIGHASH_NONE},
289     {"SINGLE", SIGHASH_SINGLE},
290     {"ALL|ANYONECANPAY", SIGHASH_ALL|SIGHASH_ANYONECANPAY},
291     {"NONE|ANYONECANPAY", SIGHASH_NONE|SIGHASH_ANYONECANPAY},
292     {"SINGLE|ANYONECANPAY", SIGHASH_SINGLE|SIGHASH_ANYONECANPAY},
293 };
294
295 static bool findSighashFlags(int& flags, const string& flagStr)
296 {
297     flags = 0;
298
299     for (unsigned int i = 0; i < N_SIGHASH_OPTS; i++) {
300         if (flagStr == sighashOptions[i].flagStr) {
301             flags = sighashOptions[i].flags;
302             return true;
303         }
304     }
305
306     return false;
307 }
308
309 uint256 ParseHashUO(map<string,UniValue>& o, string strKey)
310 {
311     if (!o.count(strKey))
312         return uint256();
313     return ParseHashUV(o[strKey], strKey);
314 }
315
316 vector<unsigned char> ParseHexUO(map<string,UniValue>& o, string strKey)
317 {
318     if (!o.count(strKey)) {
319         vector<unsigned char> emptyVec;
320         return emptyVec;
321     }
322     return ParseHexUV(o[strKey], strKey);
323 }
324
325 static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
326 {
327     int nHashType = SIGHASH_ALL;
328
329     if (flagStr.size() > 0)
330         if (!findSighashFlags(nHashType, flagStr))
331             throw runtime_error("unknown sighash flag/sign option");
332
333     vector<CTransaction> txVariants;
334     txVariants.push_back(tx);
335
336     // mergedTx will end up with all the signatures; it
337     // starts as a clone of the raw tx:
338     CMutableTransaction mergedTx(txVariants[0]);
339     bool fComplete = true;
340     CCoinsView viewDummy;
341     CCoinsViewCache view(&viewDummy);
342
343     if (!registers.count("privatekeys"))
344         throw runtime_error("privatekeys register variable must be set.");
345     bool fGivenKeys = false;
346     CBasicKeyStore tempKeystore;
347     UniValue keysObj = registers["privatekeys"];
348     fGivenKeys = true;
349
350     for (size_t kidx = 0; kidx < keysObj.size(); kidx++) {
351         if (!keysObj[kidx].isStr())
352             throw runtime_error("privatekey not a string");
353         CBitcoinSecret vchSecret;
354         bool fGood = vchSecret.SetString(keysObj[kidx].getValStr());
355         if (!fGood)
356             throw runtime_error("privatekey not valid");
357
358         CKey key = vchSecret.GetKey();
359         tempKeystore.AddKey(key);
360     }
361
362     // Add previous txouts given in the RPC call:
363     if (!registers.count("prevtxs"))
364         throw runtime_error("prevtxs register variable must be set.");
365     UniValue prevtxsObj = registers["prevtxs"];
366     {
367         for (size_t previdx = 0; previdx < prevtxsObj.size(); previdx++) {
368             UniValue prevOut = prevtxsObj[previdx];
369             if (!prevOut.isObject())
370                 throw runtime_error("expected prevtxs internal object");
371
372             map<string,UniValue::VType> types = boost::assign::map_list_of("txid", UniValue::VSTR)("vout",UniValue::VNUM)("scriptPubKey",UniValue::VSTR);
373             if (!prevOut.checkObject(types))
374                 throw runtime_error("prevtxs internal object typecheck fail");
375
376             uint256 txid = ParseHashUV(prevOut["txid"], "txid");
377
378             int nOut = atoi(prevOut["vout"].getValStr());
379             if (nOut < 0)
380                 throw runtime_error("vout must be positive");
381
382             vector<unsigned char> pkData(ParseHexUV(prevOut["scriptPubKey"], "scriptPubKey"));
383             CScript scriptPubKey(pkData.begin(), pkData.end());
384
385             {
386                 CCoinsModifier coins = view.ModifyCoins(txid);
387                 if (coins->IsAvailable(nOut) && coins->vout[nOut].scriptPubKey != scriptPubKey) {
388                     string err("Previous output scriptPubKey mismatch:\n");
389                     err = err + coins->vout[nOut].scriptPubKey.ToString() + "\nvs:\n"+
390                         scriptPubKey.ToString();
391                     throw runtime_error(err);
392                 }
393                 if ((unsigned int)nOut >= coins->vout.size())
394                     coins->vout.resize(nOut+1);
395                 coins->vout[nOut].scriptPubKey = scriptPubKey;
396                 coins->vout[nOut].nValue = 0; // we don't know the actual output value
397             }
398
399             // if redeemScript given and private keys given,
400             // add redeemScript to the tempKeystore so it can be signed:
401             if (fGivenKeys && scriptPubKey.IsPayToScriptHash() &&
402                 prevOut.exists("redeemScript")) {
403                 UniValue v = prevOut["redeemScript"];
404                 vector<unsigned char> rsData(ParseHexUV(v, "redeemScript"));
405                 CScript redeemScript(rsData.begin(), rsData.end());
406                 tempKeystore.AddCScript(redeemScript);
407             }
408         }
409     }
410
411     const CKeyStore& keystore = tempKeystore;
412
413     bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
414
415     // Sign what we can:
416     for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
417         CTxIn& txin = mergedTx.vin[i];
418         const CCoins* coins = view.AccessCoins(txin.prevout.hash);
419         if (!coins || !coins->IsAvailable(txin.prevout.n)) {
420             fComplete = false;
421             continue;
422         }
423         const CScript& prevPubKey = coins->vout[txin.prevout.n].scriptPubKey;
424
425         txin.scriptSig.clear();
426         // Only sign SIGHASH_SINGLE if there's a corresponding output:
427         if (!fHashSingle || (i < mergedTx.vout.size()))
428             SignSignature(keystore, prevPubKey, mergedTx, i, nHashType);
429
430         // ... and merge in other signatures:
431         BOOST_FOREACH(const CTransaction& txv, txVariants) {
432             txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
433         }
434         if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i)))
435             fComplete = false;
436     }
437
438     if (fComplete) {
439         // do nothing... for now
440         // perhaps store this for later optional JSON output
441     }
442
443     tx = mergedTx;
444 }
445
446 class Secp256k1Init
447 {
448 public:
449     Secp256k1Init() { ECC_Start(); }
450     ~Secp256k1Init() { ECC_Stop(); }
451 };
452
453 static void MutateTx(CMutableTransaction& tx, const string& command,
454                      const string& commandVal)
455 {
456     boost::scoped_ptr<Secp256k1Init> ecc;
457
458     if (command == "nversion")
459         MutateTxVersion(tx, commandVal);
460     else if (command == "locktime")
461         MutateTxLocktime(tx, commandVal);
462
463     else if (command == "delin")
464         MutateTxDelInput(tx, commandVal);
465     else if (command == "in")
466         MutateTxAddInput(tx, commandVal);
467
468     else if (command == "delout")
469         MutateTxDelOutput(tx, commandVal);
470     else if (command == "outaddr")
471         MutateTxAddOutAddr(tx, commandVal);
472     else if (command == "outscript")
473         MutateTxAddOutScript(tx, commandVal);
474
475     else if (command == "sign") {
476         if (!ecc) { ecc.reset(new Secp256k1Init()); }
477         MutateTxSign(tx, commandVal);
478     }
479
480     else if (command == "load")
481         RegisterLoad(commandVal);
482
483     else if (command == "set")
484         RegisterSet(commandVal);
485
486     else
487         throw runtime_error("unknown command");
488 }
489
490 static void OutputTxJSON(const CTransaction& tx)
491 {
492     UniValue entry(UniValue::VOBJ);
493     TxToUniv(tx, uint256(), entry);
494
495     string jsonOutput = entry.write(4);
496     fprintf(stdout, "%s\n", jsonOutput.c_str());
497 }
498
499 static void OutputTxHash(const CTransaction& tx)
500 {
501     string strHexHash = tx.GetHash().GetHex(); // the hex-encoded transaction hash (aka the transaction id)
502
503     fprintf(stdout, "%s\n", strHexHash.c_str());
504 }
505
506 static void OutputTxHex(const CTransaction& tx)
507 {
508     string strHex = EncodeHexTx(tx);
509
510     fprintf(stdout, "%s\n", strHex.c_str());
511 }
512
513 static void OutputTx(const CTransaction& tx)
514 {
515     if (GetBoolArg("-json", false))
516         OutputTxJSON(tx);
517     else if (GetBoolArg("-txid", false))
518         OutputTxHash(tx);
519     else
520         OutputTxHex(tx);
521 }
522
523 static string readStdin()
524 {
525     char buf[4096];
526     string ret;
527
528     while (!feof(stdin)) {
529         size_t bread = fread(buf, 1, sizeof(buf), stdin);
530         ret.append(buf, bread);
531         if (bread < sizeof(buf))
532             break;
533     }
534
535     if (ferror(stdin))
536         throw runtime_error("error reading stdin");
537
538     boost::algorithm::trim_right(ret);
539
540     return ret;
541 }
542
543 static int CommandLineRawTx(int argc, char* argv[])
544 {
545     string strPrint;
546     int nRet = 0;
547     try {
548         // Skip switches; Permit common stdin convention "-"
549         while (argc > 1 && IsSwitchChar(argv[1][0]) &&
550                (argv[1][1] != 0)) {
551             argc--;
552             argv++;
553         }
554
555         CTransaction txDecodeTmp;
556         int startArg;
557
558         if (!fCreateBlank) {
559             // require at least one param
560             if (argc < 2)
561                 throw runtime_error("too few parameters");
562
563             // param: hex-encoded bitcoin transaction
564             string strHexTx(argv[1]);
565             if (strHexTx == "-")                 // "-" implies standard input
566                 strHexTx = readStdin();
567
568             if (!DecodeHexTx(txDecodeTmp, strHexTx))
569                 throw runtime_error("invalid transaction encoding");
570
571             startArg = 2;
572         } else
573             startArg = 1;
574
575         CMutableTransaction tx(txDecodeTmp);
576
577         for (int i = startArg; i < argc; i++) {
578             string arg = argv[i];
579             string key, value;
580             size_t eqpos = arg.find('=');
581             if (eqpos == string::npos)
582                 key = arg;
583             else {
584                 key = arg.substr(0, eqpos);
585                 value = arg.substr(eqpos + 1);
586             }
587
588             MutateTx(tx, key, value);
589         }
590
591         OutputTx(tx);
592     }
593
594     catch (const boost::thread_interrupted&) {
595         throw;
596     }
597     catch (const std::exception& e) {
598         strPrint = string("error: ") + e.what();
599         nRet = EXIT_FAILURE;
600     }
601     catch (...) {
602         PrintExceptionContinue(NULL, "CommandLineRawTx()");
603         throw;
604     }
605
606     if (strPrint != "") {
607         fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
608     }
609     return nRet;
610 }
611
612 int main(int argc, char* argv[])
613 {
614     SetupEnvironment();
615
616     try {
617         if(!AppInitRawTx(argc, argv))
618             return EXIT_FAILURE;
619     }
620     catch (const std::exception& e) {
621         PrintExceptionContinue(&e, "AppInitRawTx()");
622         return EXIT_FAILURE;
623     } catch (...) {
624         PrintExceptionContinue(NULL, "AppInitRawTx()");
625         return EXIT_FAILURE;
626     }
627
628     int ret = EXIT_FAILURE;
629     try {
630         ret = CommandLineRawTx(argc, argv);
631     }
632     catch (const std::exception& e) {
633         PrintExceptionContinue(&e, "CommandLineRawTx()");
634     } catch (...) {
635         PrintExceptionContinue(NULL, "CommandLineRawTx()");
636     }
637     return ret;
638 }
This page took 0.058033 seconds and 4 git commands to generate.