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